Compare commits

..

141 Commits

Author SHA1 Message Date
Niels Lohmann c13ecd5344 💚 add trait for 128 bit integers 2020-07-13 14:03:04 +02:00
Niels Lohmann 0f1f5052bf 💚 add trait for 128 bit integers 2020-07-13 13:46:56 +02:00
Niels Lohmann e3aace6dac 🔊 add test for type traits 2020-07-13 13:23:36 +02:00
Niels Lohmann 039c97694d 🔥 remove failing test 2020-07-13 12:51:39 +02:00
Niels Lohmann 23496a3abf 🔊 add test for type traits 2020-07-13 12:44:34 +02:00
Niels Lohmann bffa18b46e ♻️ replace alternative operator 2020-07-12 17:44:39 +02:00
Niels Lohmann de4933e093 🎨 fix format 2020-07-12 17:39:36 +02:00
Niels Lohmann aba37d001e Merge branch 'develop' of https://github.com/nlohmann/json into issue2228 2020-07-12 17:39:13 +02:00
Niels Lohmann cf741313b3 📝 add Clang on Windows to CI list 2020-07-12 15:31:17 +02:00
Niels Lohmann e316f5c5b6 Merge pull request #2258 from nlohmann/issue2179
Add ordered_json specialization with ordered object keys
2020-07-12 13:11:23 +02:00
Niels Lohmann 486812904f Merge pull request #2259 from nlohmann/clang_windows
Make library work with Clang on Windows
2020-07-12 13:09:35 +02:00
Niels Lohmann 4d28694756 ♻️ replace further alternative operators 2020-07-11 19:28:58 +02:00
Niels Lohmann 738c83d6af 💚 add test for ordered_map 2020-07-11 19:24:32 +02:00
Niels Lohmann 8d295235a5 🔥 remove unused boolean_operators.hpp header 2020-07-11 19:20:44 +02:00
Niels Lohmann 6477b9b20a ♻️ replace further alternative operators 2020-07-11 14:09:06 +02:00
Niels Lohmann 7f923424b3 🔀 merge develop branch and resolve conflicts 2020-07-11 14:05:02 +02:00
Niels Lohmann dc06f100be Merge branch 'develop' of https://github.com/nlohmann/json into clang_windows
 Conflicts:
	include/nlohmann/detail/input/binary_reader.hpp
	include/nlohmann/detail/input/json_sax.hpp
	include/nlohmann/detail/input/lexer.hpp
	include/nlohmann/detail/input/parser.hpp
	include/nlohmann/detail/json_pointer.hpp
	include/nlohmann/detail/output/serializer.hpp
	include/nlohmann/json.hpp
	single_include/nlohmann/json.hpp
2020-07-11 14:04:40 +02:00
Niels Lohmann 889f269a6c ♻️ replace further alternative operators 2020-07-11 13:51:25 +02:00
Niels Lohmann b2240f7508 🏁 remove failing code for Clang/Windows 2020-07-11 13:46:04 +02:00
Niels Lohmann 609a0046c4 ♻️ replace further alternative operators 2020-07-11 13:39:14 +02:00
Niels Lohmann 3a80823ff8 🔀 merge develop branch and resolve conflicts 2020-07-11 13:21:13 +02:00
Niels Lohmann 9c21285133 Merge branch 'develop' of https://github.com/nlohmann/json into issue2179
 Conflicts:
	single_include/nlohmann/json.hpp
2020-07-11 13:20:16 +02:00
Niels Lohmann 5f146cb853 Merge pull request #2206 from gatopeich/issue2179
Simple ordered_json that works on all supported compilers
2020-07-11 13:15:40 +02:00
gatopeich 47d154dd49 Remove redundant comment 2020-07-11 00:34:12 +01:00
gatopeich f9a1fec272 Remove redundant comment 2020-07-11 00:34:02 +01:00
Niels Lohmann cbafed3494 ⬇️ require CMake 3.1 2020-07-10 12:53:48 +02:00
Niels Lohmann b6d0a4ab30 Merge branch 'develop' of https://github.com/nlohmann/json into issue2228 2020-07-10 12:46:43 +02:00
Niels Lohmann 2c231f9567 💚 remove failing test 2020-07-10 12:46:31 +02:00
Niels Lohmann 7fbcae2679 🚨 fix a warning 2020-07-09 22:17:59 +02:00
gatopeich f62b4626be Removing comment about AllocatorType per review request 2020-07-09 21:12:14 +01:00
Niels Lohmann 3aa4c0b827 add tests for number types 2020-07-09 22:07:07 +02:00
gatopeich 0eb7b0a991 Update README.md per review comments
Co-authored-by: Niels Lohmann <niels.lohmann@gmail.com>
2020-07-09 20:47:19 +01:00
Niels Lohmann 612f326052 ♻️ add proper SFINAE for 64 bit check 2020-07-09 21:31:01 +02:00
Niels Lohmann 75d5d05993 Merge pull request #2253 from ericonr/pkgconf
Add pkg-config file
2020-07-09 20:42:42 +02:00
Niels Lohmann 4c7bd014d9 Merge pull request #2242 from nlohmann/issue2239
Make assert configurable via JSON_ASSERT
2020-07-09 15:13:12 +02:00
Niels Lohmann 0c4e6aa2cd ♻️ move integer conversion out of scan_number 2020-07-09 14:21:39 +02:00
Niels Lohmann d740622f96 📝 add documentation for macros 2020-07-09 13:23:33 +02:00
Érico Rolim 251fce819c README: add explanation on how to use pkg-config. 2020-07-09 03:59:53 -03:00
Palmer Dabbelt c7d18c1625 cmake: Generate and install a pkg-config file.
The meson builds install a pkg-config file, but the cmake builds don't.
This adds a pkg-config file to the cmake builds that is functionally
equivalent to the one generated from meson.
2020-07-09 03:59:53 -03:00
Niels Lohmann 0306525cdb Merge pull request #2251 from nlohmann/fix_2181
Fix regression from #2181
2020-07-09 07:33:03 +02:00
Niels Lohmann f774a32d2b fix test 2020-07-08 14:47:22 +02:00
Niels Lohmann e3e9ccfc02 🚑 fix regression from #2181 2020-07-08 14:02:28 +02:00
Niels Lohmann 1b04092c5c fix test 2020-07-08 12:38:46 +02:00
Niels Lohmann d019ddfcdb 👷 add code scanning 2020-07-08 12:25:53 +02:00
Niels Lohmann 28ef87370b 🚨 fix warning 2020-07-06 13:19:06 +02:00
Niels Lohmann 99fc6b16ab Merge branch 'develop' of https://github.com/nlohmann/json into issue2239 2020-07-06 12:52:59 +02:00
Niels Lohmann ba8174041e add test case for JSON_ASSERT 2020-07-06 12:52:48 +02:00
Niels Lohmann efcc826ecb 🚨 fix warning 2020-07-06 12:37:39 +02:00
Niels Lohmann 98b1c6d302 🚩 use JSON_ASSERT(x) instead of assert(x) 2020-07-06 12:22:31 +02:00
Niels Lohmann b04dc055b2 Merge pull request #2233 from nlohmann/issue2175
Add specialization of get_to
2020-07-06 07:58:52 +02:00
Niels Lohmann 197c3d4fb0 Merge pull request #2232 from nlohmann/ignore_documentation
Refine documentation of error_handler parameter
2020-07-06 07:58:28 +02:00
Agustín F. Pozuelo 803c16e5af Clean-up unintended changes to whitespace 2020-07-03 10:26:05 +01:00
Agustín F. Pozuelo 25f5d75e6e Fix compilation for xcode 9.x 2020-07-03 01:44:18 +01:00
Agustín F. Pozuelo 93770467a1 Precisely 4 template arguments for the sake of clang 3.6 (?) 2020-07-03 01:28:54 +01:00
Agustín F. Pozuelo 0fc261f0f2 Make ordered_map compatible with GCC 5.5 2020-07-03 00:33:31 +01:00
Niels Lohmann f59f4a2b61 💚 fix build 2020-06-30 19:55:40 +02:00
Niels Lohmann c7e079cc98 🚑 add specialization of get_to #2175 2020-06-30 14:26:52 +02:00
Niels Lohmann ad6eadeb70 📝 refine documentation of error_handler parameter 2020-06-30 13:59:43 +02:00
gatopeich 49f26a0250 Have 4 template parameters for ordered_map 2020-06-29 17:32:55 +01:00
Niels Lohmann eb7376bb13 Merge pull request #2225 from nlohmann/issue2175
Simplify conversion from/to custom types
2020-06-29 14:41:09 +02:00
Niels Lohmann 470f7c0c68 📝 add documentation 2020-06-29 13:43:06 +02:00
Niels Lohmann 1b4ea8f89b Merge pull request #2224 from nlohmann/issue2221
Remove unused typedefs
2020-06-28 15:08:18 +02:00
Niels Lohmann d7a2956b24 🔀 merge from develop 2020-06-27 13:16:20 +02:00
Niels Lohmann ac3922c7aa Merge branch 'develop' of https://github.com/nlohmann/json into clang_windows
 Conflicts:
	include/nlohmann/detail/input/binary_reader.hpp
	include/nlohmann/detail/input/input_adapters.hpp
	include/nlohmann/detail/input/lexer.hpp
	include/nlohmann/detail/output/binary_writer.hpp
	include/nlohmann/json.hpp
	single_include/nlohmann/json.hpp
2020-06-27 13:14:48 +02:00
Niels Lohmann fa9f4040df 🔥 remove unused typedefs #2221 2020-06-27 13:07:02 +02:00
Niels Lohmann 5ba0f65c34 🔧 remove feature request template 2020-06-27 12:55:41 +02:00
Niels Lohmann aefa0b3e86 🔧 use Github discussions for questions 2020-06-27 12:54:42 +02:00
Niels Lohmann 3948b5b091 Merge pull request #2212 from nlohmann/comments
Add option to ignore comments in parse/accept functions
2020-06-27 12:44:51 +02:00
Niels Lohmann 1af4f5f360 Merge pull request #2222 from alexreinking/patch-1
Enable CMake policy CMP0077
2020-06-27 12:43:52 +02:00
Niels Lohmann c5ee222982 Merge pull request #2211 from nlohmann/fix_warnings
Fix Clang-Tidy warnings
2020-06-27 12:34:18 +02:00
Alex Reinking ec43371e07 Enable CMake policy CMP0077
Projects that import json via [FetchContent](https://cmake.org/cmake/help/latest/module/FetchContent.html) or `add_subdirectory` pointed at a git submodule may want to set `JSON_BuildTests` to "NO". However, this doesn't work without creating an identical `option()` in the importing project. Enabling CMP0077 in supported versions of CMake changes the behavior of `option()` to allow importing projects to set default values for the variables without touching the cache.

See the documentation for CMP0077 here: https://cmake.org/cmake/help/latest/policy/CMP0077.html
2020-06-26 11:47:36 -07:00
Niels Lohmann 635b9a0ae4 Merge pull request #2193 from dota17/issue#2059
Fix consistency in function `int_to_string()`
2020-06-24 11:46:48 +02:00
gatopeich cf18ba2394 Test initialization with dup keys 2020-06-23 17:50:51 +01:00
gatopeich 08963d6826 Revert types.md 2020-06-23 15:48:02 +01:00
gatopeich d08fca2bb9 Use const Key in ordered map
(forgotten in previous commit!)
2020-06-23 15:44:46 +01:00
gatopeich 5e7bdf1cab Roll-back to hard-coded object_t::value_type 2020-06-23 15:39:00 +01:00
gatopeich fb8c11f25c Re-implement ordered_map::erase,
so that it can handle pair<const Key,...>
2020-06-23 15:01:20 +01:00
gatopeich acd748e16f Use std::map default allocator as a placeholder
to extract the actual ObjectType::value_type
Still fails on older compilers (GCC <= 5.5)
2020-06-23 12:03:21 +01:00
gatopeich 49623a75ee Revert "Using ordered_json instead of fifo_map in test-regression"
This reverts commit 5fe3d3929a.
2020-06-23 11:30:52 +01:00
Niels Lohmann 8575fdf9ad Merge pull request #2181 from dota17/issue#1275
Fix issue#1275
2020-06-23 09:23:03 +02:00
Niels Lohmann 4bfe4add20 Merge pull request #2203 from t-b/use-unsigned-indizies-for-array-index-in-json-pointer
Use unsigned indizies for array index in json pointer
2020-06-23 09:16:01 +02:00
chenguoping 0ecf297457 drop std::enable_if part 2020-06-23 09:14:55 +08:00
Niels Lohmann a9809f3381 🏁 revert change that breaks with MSVC 2020-06-22 23:02:28 +02:00
Niels Lohmann 8b3d2399a4 🚨 remove warnings 2020-06-22 22:32:21 +02:00
gatopeich 5fe3d3929a Using ordered_json instead of fifo_map in test-regression
This is more comprehensive and the "my_workaround_fifo_map" wrapper does not allow to infer value type as required in this branch.

This reverts commit 064a9c9212.
2020-06-22 19:10:35 +01:00
gatopeich 064a9c9212 Fix regression test 2020-06-22 18:59:19 +01:00
gatopeich ddf0a45abb Use AllocatorType<ObjectType::value_type>,
instead of hard-coding it for std::map's value_type
2020-06-22 18:35:46 +01:00
chenguoping aeef50709e to allow for ADL in int_to_string() function 2020-06-22 20:17:56 +08:00
Thomas Braun ecbb2756fd json_pointer::array_index: Use unsigned values for the array index when parsing
The current code uses std::stoi to convert the input string to an int
array_index. This limits the maximum addressable array size to ~2GB on
most platforms.

But all callers immediately convert the result of array_index to
BasicJsonType::size_type.

So let's parse it as unsigned long long, which allows us to have as
big arrays as available memory. And also makes the call sites nicer to
read.

One complication arises on platforms where size_type is smaller than
unsigned long long. We need to bail out on these if the parsed array
index does not fit into size_type.
2020-06-22 13:42:55 +02:00
Niels Lohmann 65e8ee985a 🔨 clean up 2020-06-22 08:59:03 +02:00
gatopeich 15337b2cc3 Ignore allocator hardcoded to match std::map 2020-06-22 00:03:48 +01:00
gatopeich 27aaf6f845 Clean-up ordered_map declarations 2020-06-21 22:28:03 +01:00
Niels Lohmann 29ad2178c6 Merge pull request #2176 from gracicot/cpp20-support-no-std-fct-templ-specialization
C++20 support by removing swap specialization
2020-06-21 20:39:58 +02:00
Niels Lohmann e22ce45065 🚸 improve diagnostics 2020-06-21 13:28:00 +02:00
Niels Lohmann 139a0258cc Merge branch 'develop' of https://github.com/nlohmann/json into comments 2020-06-21 12:40:21 +02:00
Niels Lohmann 8dade80499 Merge pull request #2202 from nlohmann/issue2189
Add option to not rely on Internet connectivity during test stage
2020-06-21 08:41:48 +02:00
Thomas Braun f0e73163f2 json_pointer.hpp: Mention more exception in documentation
Forgotten in dcd3a6c6 (move the catch of std::invalid_argument into
array_index(), 2020-03-23).
2020-06-20 15:27:22 +02:00
Niels Lohmann 0fe9f23254 add macros from #2175 2020-06-20 14:11:37 +02:00
Niels Lohmann 6ee9e5f402 ⚗️ remove const from value type 2020-06-20 13:23:44 +02:00
Niels Lohmann 24992003d9 📝 add notes from #2189 2020-06-20 09:55:11 +02:00
Niels Lohmann e4675887a6 Merge branch 'develop' of https://github.com/nlohmann/json into issue2189 2020-06-20 09:47:12 +02:00
Niels Lohmann 74c6e4295f Merge pull request #2201 from nlohmann/issue2196
Serialize floating-point numbers with 32 bit when possible (MessagePack)
2020-06-20 09:31:02 +02:00
Niels Lohmann 4fd0d02b6f 🚧 toward an ordered_json type 2020-06-19 15:27:05 +02:00
Niels Lohmann b64002bbca ♻️ extract common code to function 2020-06-19 13:24:08 +02:00
Niels Lohmann 0585ecc56b add tests for comment skipping 2020-06-19 13:10:35 +02:00
Niels Lohmann cd115cbc33 update test suite 2020-06-18 12:50:32 +02:00
Niels Lohmann 74520d8bb0 🚧 extend API 2020-06-17 22:03:14 +02:00
Niels Lohmann 88a37010d6 🐛 serialize 32-bit floating-point numbers as float 32 in MessagePack (0xCA) #2196 2020-06-17 21:14:23 +02:00
Niels Lohmann e9bfcf7255 improve comment parsing 2020-06-17 14:59:47 +02:00
chenguoping 4a6c68c7eb drop new blank line 2020-06-17 20:44:31 +08:00
chenguoping da8fa3535a drop testcase 2020-06-17 20:41:31 +08:00
Niels Lohmann e86b3fae98 🔧 add label to tests that require a git checkout 2020-06-17 12:35:59 +02:00
chenguoping f466919ec2 change test cases 2020-06-17 15:07:25 +08:00
chenguoping 8aaa4013a3 remove overload function, change default_value to rvalue 2020-06-17 15:05:28 +08:00
Niels Lohmann 4d96f4cf6a 🔧 overwork CMake files 2020-06-16 20:23:01 +02:00
Niels Lohmann f4c4bab600 add option JSON_TestDataDirectory to set path with test data #2189 2020-06-16 12:55:36 +02:00
Niels Lohmann b53c6e2f81 ignore comments 2020-06-16 12:28:59 +02:00
chenguoping 691fb0c57a fix issue#2059 2020-06-16 15:35:26 +08:00
chenguoping a3df26b771 add some test cases 2020-06-10 19:27:57 +08:00
chenguoping 71830be06d fix issue#1275 2020-06-10 19:27:28 +08:00
Guillaume Racicot 82fbbeeac5 Adapted unit tests to use ADL calls for swap like the new swappable concept 2020-06-06 12:28:52 -04:00
Guillaume Racicot 225c8f150a Disable std::swap specialization in C++20 and added a friend swap function 2020-06-06 11:36:39 -04:00
Niels Lohmann 24e8562664 👷 remove Clang 8 2020-06-04 12:48:03 +02:00
Niels Lohmann a53e3a5443 👷 try Clang 8 2020-06-04 12:34:56 +02:00
Niels Lohmann dc323314d5 👷 try Clang 10 2020-06-04 12:29:53 +02:00
Niels Lohmann 402c34c526 👷 try Clang 10 2020-06-04 12:27:37 +02:00
Niels Lohmann 65c4b07451 🎨 replace alternative operators (and, not, or) 2020-06-03 21:22:07 +02:00
Niels Lohmann 0498202a03 🎨 replace alternative operators (and, not, or) 2020-06-03 14:20:36 +02:00
Niels Lohmann 4f04ea1bef Merge branches 'clang_windows' and 'develop' of https://github.com/nlohmann/json into clang_windows 2020-06-03 14:01:18 +02:00
Niels Lohmann 5ea205f570 👷 install clang 2020-05-30 18:17:54 +02:00
Niels Lohmann 5f10d5d156 👷 install clang 2020-05-30 18:15:13 +02:00
Niels Lohmann 7c0c522b96 👷 install clang 2020-05-30 18:11:54 +02:00
Niels Lohmann 522ec5d7bd 👷 install clang 2020-05-30 18:06:52 +02:00
Niels Lohmann 7e5c2a480a 👷 install clang 2020-05-30 18:04:07 +02:00
Niels Lohmann 9c971c2d2f 👷 install clang 2020-05-30 17:40:27 +02:00
Niels Lohmann 4ba8c95794 👷 install clang 2020-05-30 13:41:18 +02:00
Niels Lohmann fbd3e8f677 👷 install clang 2020-05-30 13:35:19 +02:00
Niels Lohmann 0309025b45 👷 set full path 2020-05-30 13:28:44 +02:00
Niels Lohmann 9191926fff 👷 use Makefiles 2020-05-30 13:23:13 +02:00
Niels Lohmann 42ef2a5adb 👷 use Clang compiler 2020-05-30 13:15:56 +02:00
Niels Lohmann 2182935397 👷 add Clang/Windows step 2020-05-30 13:07:23 +02:00
78 changed files with 3916 additions and 2386 deletions
+12 -15
View File
@@ -1,23 +1,20 @@
Checks: '-*, Checks: '*,
bugprone-*, -cppcoreguidelines-avoid-goto,
cert-*, -cppcoreguidelines-avoid-magic-numbers,
clang-analyzer-*, -cppcoreguidelines-macro-usage,
google-*, -fuchsia-default-arguments-calls,
-google-runtime-references, -fuchsia-default-arguments-declarations,
-fuchsia-overloaded-operator,
-google-explicit-constructor, -google-explicit-constructor,
hicpp-*, -google-runtime-references,
-hicpp-avoid-goto,
-hicpp-explicit-conversions,
-hicpp-no-array-decay, -hicpp-no-array-decay,
-hicpp-uppercase-literal-suffix, -hicpp-uppercase-literal-suffix,
-hicpp-explicit-conversions,
misc-*,
-misc-non-private-member-variables-in-classes,
llvm-*,
-llvm-header-guard, -llvm-header-guard,
modernize-*, -llvm-include-order,
-misc-non-private-member-variables-in-classes,
-modernize-use-trailing-return-type, -modernize-use-trailing-return-type,
performance-*,
portability-*,
readability-*,
-readability-magic-numbers, -readability-magic-numbers,
-readability-uppercase-literal-suffix' -readability-uppercase-literal-suffix'
-16
View File
@@ -1,16 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: 'kind: enhancement/improvement'
assignees: ''
---
#### Which feature do you want to see in the library?
<!-- Describe the feature in as much detail as possible. -->
#### How would the feature be usable for other users?
<!-- Include sample usage where appropriate. -->
+5
View File
@@ -0,0 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: Ask a question
url: https://github.com/nlohmann/json/discussions
about: Ask questions and discuss with other community members
-40
View File
@@ -1,40 +0,0 @@
---
name: Question
about: Ask a question regarding the library.
title: ''
labels: 'kind: question'
assignees: ''
---
<!-- Provide a concise summary of the issue in the title above. -->
#### What do you want to achieve?
<!-- Please describe the feature as detailed as possible. -->
#### What have you tried?
<!-- There are thousands of issues to search: https://github.com/nlohmann/json/issues?q=is%3Aissue+ -->
<!-- There is a full documentation of the API: https://nlohmann.github.io/json/ -->
<!-- There is a detailed README file: https://github.com/nlohmann/json/blob/develop/README.md -->
#### Can you provide a small code example?
<!-- Please understand that we cannot analyze and debug large code bases. -->
#### Which compiler and operating system are you using?
<!-- Include as many relevant details about the environment you experienced the bug in. -->
<!-- Make sure you use a supported compiler, see https://github.com/nlohmann/json#supported-compilers. -->
- Compiler: ___
- Operating system: ___
#### Which version of the library did you use?
<!-- Please add an `x` to the respective line. -->
- [ ] latest release version 3.7.3
- [ ] other release - please state the version: ___
- [ ] the `develop` branch
+54
View File
@@ -0,0 +1,54 @@
name: "Code scanning - action"
on:
push:
branches: [develop, ]
pull_request:
# The branches below must be a subset of the branches above
branches: [develop]
schedule:
- cron: '0 19 * * 1'
jobs:
CodeQL-Build:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
fetch-depth: 2
# If this run was triggered by a pull request event, then checkout
# the head of the pull request instead of the merge commit.
- run: git checkout HEAD^2
if: ${{ github.event_name == 'pull_request' }}
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
# Override language selection by uncommenting this and choosing your languages
# with:
# languages: go, javascript, csharp, python, cpp, java
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
+32
View File
@@ -0,0 +1,32 @@
name: Windows
on: [push, pull_request]
jobs:
clang9:
runs-on: windows-latest
steps:
- uses: actions/checkout@v1
- name: install Clang
run: curl -fsSL -o LLVM9.exe https://releases.llvm.org/9.0.0/LLVM-9.0.0-win64.exe ; 7z x LLVM9.exe -y -o"C:/Program Files/LLVM"
- name: cmake
run: cmake -S . -B build -DCMAKE_CXX_COMPILER="C:/Program Files/LLVM/bin/clang++.exe" -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE=Debug -DJSON_BuildTests=On
- name: build
run: cmake --build build --parallel 10
- name: test
run: cd build ; ctest -j 10 -C Debug --exclude-regex "test-unicode" --output-on-failure
clang10:
runs-on: windows-latest
steps:
- uses: actions/checkout@v1
- name: install Clang
run: curl -fsSL -o LLVM10.exe https://github.com/llvm/llvm-project/releases/download/llvmorg-10.0.0/LLVM-10.0.0-win64.exe ; 7z x LLVM10.exe -y -o"C:/Program Files/LLVM"
- name: cmake
run: cmake -S . -B build -DCMAKE_CXX_COMPILER="C:/Program Files/LLVM/bin/clang++.exe" -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE=Debug -DJSON_BuildTests=On
- name: build
run: cmake --build build --parallel 10
- name: test
run: cd build ; ctest -j 10 -C Debug --exclude-regex "test-unicode" --output-on-failure
+16
View File
@@ -15,6 +15,12 @@ include(ExternalProject)
## ##
## OPTIONS ## OPTIONS
## ##
if (POLICY CMP0077)
# Allow CMake 3.13+ to override options when using FetchContent / add_subdirectory.
cmake_policy(SET CMP0077 NEW)
endif ()
option(JSON_BuildTests "Build the unit tests when BUILD_TESTING is enabled." ON) option(JSON_BuildTests "Build the unit tests when BUILD_TESTING is enabled." ON)
option(JSON_Install "Install CMake targets during install step." ON) option(JSON_Install "Install CMake targets during install step." ON)
option(JSON_MultipleHeaders "Use non-amalgamated version of the library." OFF) option(JSON_MultipleHeaders "Use non-amalgamated version of the library." OFF)
@@ -73,6 +79,12 @@ if (MSVC)
) )
endif() endif()
# Install a pkg-config file, so other tools can find this.
CONFIGURE_FILE(
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/pkg-config.pc.in"
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc"
)
## ##
## TESTS ## TESTS
## create and configure the unit test target ## create and configure the unit test target
@@ -133,4 +145,8 @@ endif()
NAMESPACE ${PROJECT_NAME}:: NAMESPACE ${PROJECT_NAME}::
DESTINATION ${NLOHMANN_JSON_CONFIG_INSTALL_DIR} DESTINATION ${NLOHMANN_JSON_CONFIG_INSTALL_DIR}
) )
install(
FILES "${CMAKE_BINARY_DIR}/${PROJECT_NAME}.pc"
DESTINATION lib/pkgconfig
)
endif() endif()
+6 -4
View File
@@ -97,6 +97,7 @@ doctest:
# -Wno-exit-time-destructors: warning in json code triggered by NLOHMANN_JSON_SERIALIZE_ENUM # -Wno-exit-time-destructors: warning in json code triggered by NLOHMANN_JSON_SERIALIZE_ENUM
# -Wno-float-equal: not all comparisons in the tests can be replaced by Approx # -Wno-float-equal: not all comparisons in the tests can be replaced by Approx
# -Wno-keyword-macro: unit-tests use "#define private public" # -Wno-keyword-macro: unit-tests use "#define private public"
# -Wno-missing-prototypes: for NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE
# -Wno-padded: padding is nothing to warn about # -Wno-padded: padding is nothing to warn about
# -Wno-range-loop-analysis: items tests "for(const auto i...)" # -Wno-range-loop-analysis: items tests "for(const auto i...)"
# -Wno-switch-enum -Wno-covered-switch-default: pedantic/contradicting warnings about switches # -Wno-switch-enum -Wno-covered-switch-default: pedantic/contradicting warnings about switches
@@ -113,6 +114,7 @@ pedantic_clang:
-Wno-exit-time-destructors \ -Wno-exit-time-destructors \
-Wno-float-equal \ -Wno-float-equal \
-Wno-keyword-macro \ -Wno-keyword-macro \
-Wno-missing-prototypes \
-Wno-padded \ -Wno-padded \
-Wno-range-loop-analysis \ -Wno-range-loop-analysis \
-Wno-switch-enum -Wno-covered-switch-default \ -Wno-switch-enum -Wno-covered-switch-default \
@@ -253,7 +255,7 @@ pedantic_gcc:
-Wmismatched-tags \ -Wmismatched-tags \
-Wmissing-attributes \ -Wmissing-attributes \
-Wmissing-braces \ -Wmissing-braces \
-Wmissing-declarations \ -Wno-missing-declarations \
-Wmissing-field-initializers \ -Wmissing-field-initializers \
-Wmissing-include-dirs \ -Wmissing-include-dirs \
-Wmissing-profile \ -Wmissing-profile \
@@ -466,7 +468,7 @@ cppcheck:
clang_analyze: clang_analyze:
rm -fr clang_analyze_build rm -fr clang_analyze_build
mkdir clang_analyze_build mkdir clang_analyze_build
cd clang_analyze_build ; CCC_CXX=$(COMPILER_DIR)/clang++ CXX=$(COMPILER_DIR)/clang++ $(COMPILER_DIR)/scan-build cmake .. -GNinja -DJSON_BuildTests=On cd clang_analyze_build ; CCC_CXX=$(COMPILER_DIR)/clang++ CXX=$(COMPILER_DIR)/clang++ $(COMPILER_DIR)/scan-build cmake .. -GNinja -DJSON_BuildTests=On -DJSON_MultipleHeaders=On
cd clang_analyze_build ; \ cd clang_analyze_build ; \
$(COMPILER_DIR)/scan-build \ $(COMPILER_DIR)/scan-build \
-enable-checker alpha.core.BoolAssignment,alpha.core.CallAndMessageUnInitRefArg,alpha.core.CastSize,alpha.core.CastToStruct,alpha.core.Conversion,alpha.core.DynamicTypeChecker,alpha.core.FixedAddr,alpha.core.PointerArithm,alpha.core.PointerSub,alpha.core.SizeofPtr,alpha.core.StackAddressAsyncEscape,alpha.core.TestAfterDivZero,alpha.deadcode.UnreachableCode,core.builtin.BuiltinFunctions,core.builtin.NoReturnFunctions,core.CallAndMessage,core.DivideZero,core.DynamicTypePropagation,core.NonnilStringConstants,core.NonNullParamChecker,core.NullDereference,core.StackAddressEscape,core.UndefinedBinaryOperatorResult,core.uninitialized.ArraySubscript,core.uninitialized.Assign,core.uninitialized.Branch,core.uninitialized.CapturedBlockVariable,core.uninitialized.UndefReturn,core.VLASize,cplusplus.InnerPointer,cplusplus.Move,cplusplus.NewDelete,cplusplus.NewDeleteLeaks,cplusplus.SelfAssignment,deadcode.DeadStores,nullability.NullableDereferenced,nullability.NullablePassedToNonnull,nullability.NullableReturnedFromNonnull,nullability.NullPassedToNonnull,nullability.NullReturnedFromNonnull \ -enable-checker alpha.core.BoolAssignment,alpha.core.CallAndMessageUnInitRefArg,alpha.core.CastSize,alpha.core.CastToStruct,alpha.core.Conversion,alpha.core.DynamicTypeChecker,alpha.core.FixedAddr,alpha.core.PointerArithm,alpha.core.PointerSub,alpha.core.SizeofPtr,alpha.core.StackAddressAsyncEscape,alpha.core.TestAfterDivZero,alpha.deadcode.UnreachableCode,core.builtin.BuiltinFunctions,core.builtin.NoReturnFunctions,core.CallAndMessage,core.DivideZero,core.DynamicTypePropagation,core.NonnilStringConstants,core.NonNullParamChecker,core.NullDereference,core.StackAddressEscape,core.UndefinedBinaryOperatorResult,core.uninitialized.ArraySubscript,core.uninitialized.Assign,core.uninitialized.Branch,core.uninitialized.CapturedBlockVariable,core.uninitialized.UndefReturn,core.VLASize,cplusplus.InnerPointer,cplusplus.Move,cplusplus.NewDelete,cplusplus.NewDeleteLeaks,cplusplus.SelfAssignment,deadcode.DeadStores,nullability.NullableDereferenced,nullability.NullablePassedToNonnull,nullability.NullableReturnedFromNonnull,nullability.NullPassedToNonnull,nullability.NullReturnedFromNonnull \
@@ -488,7 +490,7 @@ clang_tidy:
pvs_studio: pvs_studio:
rm -fr pvs_studio_build rm -fr pvs_studio_build
mkdir pvs_studio_build mkdir pvs_studio_build
cd pvs_studio_build ; cmake .. -DCMAKE_EXPORT_COMPILE_COMMANDS=On cd pvs_studio_build ; cmake .. -DCMAKE_EXPORT_COMPILE_COMMANDS=On -DJSON_MultipleHeaders=On
cd pvs_studio_build ; pvs-studio-analyzer analyze -j 10 cd pvs_studio_build ; pvs-studio-analyzer analyze -j 10
cd pvs_studio_build ; plog-converter -a'GA:1,2;64:1;CS' -t fullhtml PVS-Studio.log -o pvs cd pvs_studio_build ; plog-converter -a'GA:1,2;64:1;CS' -t fullhtml PVS-Studio.log -o pvs
open pvs_studio_build/pvs/index.html open pvs_studio_build/pvs/index.html
@@ -497,7 +499,7 @@ pvs_studio:
infer: infer:
rm -fr infer_build rm -fr infer_build
mkdir infer_build mkdir infer_build
cd infer_build ; infer compile -- cmake .. ; infer run -- make -j 4 cd infer_build ; infer compile -- cmake .. -DJSON_MultipleHeaders=On ; infer run -- make -j 4
# call OCLint <http://oclint.org> static analyzer # call OCLint <http://oclint.org> static analyzer
oclint: oclint:
+63 -9
View File
@@ -27,6 +27,7 @@
- [Integration](#integration) - [Integration](#integration)
- [CMake](#cmake) - [CMake](#cmake)
- [Package Managers](#package-managers) - [Package Managers](#package-managers)
- [Pkg-config](#pkg-config)
- [Examples](#examples) - [Examples](#examples)
- [JSON as first-class data type](#json-as-first-class-data-type) - [JSON as first-class data type](#json-as-first-class-data-type)
- [Serialization / Deserialization](#serialization--deserialization) - [Serialization / Deserialization](#serialization--deserialization)
@@ -230,6 +231,20 @@ Please file issues [here](https://github.com/build2-packaging/nlohmann-json) if
If you are using [`wsjcpp`](https://wsjcpp.org), you can use the command `wsjcpp install "https://github.com/nlohmann/json:develop"` to get the latest version. Note you can change the branch ":develop" to an existing tag or another branch. If you are using [`wsjcpp`](https://wsjcpp.org), you can use the command `wsjcpp install "https://github.com/nlohmann/json:develop"` to get the latest version. Note you can change the branch ":develop" to an existing tag or another branch.
### Pkg-config
If you are using bare Makefiles, you can use `pkg-config` to generate the include flags that point to where the library is installed:
```sh
pkg-config nlohmann_json --cflags
```
Users of the Meson build system will also be able to use a system wide library, which will be found by `pkg-config`:
```meson
json = dependency('nlohmann_json', required: true)
```
## Examples ## Examples
Beside the examples below, you may want to check the [documentation](https://nlohmann.github.io/json/) where each function contains a separate code example (e.g., check out [`emplace()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a5338e282d1d02bed389d852dd670d98d.html#a5338e282d1d02bed389d852dd670d98d)). All [example files](https://github.com/nlohmann/json/tree/develop/doc/examples) can be compiled and executed on their own (e.g., file [emplace.cpp](https://github.com/nlohmann/json/blob/develop/doc/examples/emplace.cpp)). Beside the examples below, you may want to check the [documentation](https://nlohmann.github.io/json/) where each function contains a separate code example (e.g., check out [`emplace()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a5338e282d1d02bed389d852dd670d98d.html#a5338e282d1d02bed389d852dd670d98d)). All [example files](https://github.com/nlohmann/json/tree/develop/doc/examples) can be compiled and executed on their own (e.g., file [emplace.cpp](https://github.com/nlohmann/json/blob/develop/doc/examples/emplace.cpp)).
@@ -869,6 +884,42 @@ Some important things:
* In function `from_json`, use function [`at()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a93403e803947b86f4da2d1fb3345cf2c.html#a93403e803947b86f4da2d1fb3345cf2c) to access the object values rather than `operator[]`. In case a key does not exist, `at` throws an exception that you can handle, whereas `operator[]` exhibits undefined behavior. * In function `from_json`, use function [`at()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a93403e803947b86f4da2d1fb3345cf2c.html#a93403e803947b86f4da2d1fb3345cf2c) to access the object values rather than `operator[]`. In case a key does not exist, `at` throws an exception that you can handle, whereas `operator[]` exhibits undefined behavior.
* You do not need to add serializers or deserializers for STL types like `std::vector`: the library already implements these. * You do not need to add serializers or deserializers for STL types like `std::vector`: the library already implements these.
#### Simplify your life with macros
If you just want to serialize/deserialize some structs, the `to_json`/`from_json` functions can be a lot of boilerplate.
There are two macros to make your life easier as long as you (1) want to use a JSON object as serialization and (2) want to use the member variable names as object keys in that object:
- `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(name, member1, member2, ...)` is to be defined inside of the namespace of the class/struct to create code for.
- `NLOHMANN_DEFINE_TYPE_INTRUSIVE(name, member1, member2, ...)` is to be defined inside of the class/struct to create code for. This macro can also access private members.
In both macros, the first parameter is the name of the class/struct, and all remaining parameters name the members.
##### Examples
The `to_json`/`from_json` functions for the `person` struct above can be created with:
```cpp
namespace ns {
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(person, name, address, age)
}
```
Here is an example with private members, where `NLOHMANN_DEFINE_TYPE_INTRUSIVE` is needed:
```cpp
namespace ns {
class address {
private:
std::string street;
int housenumber;
int postcode;
public:
NLOHMANN_DEFINE_TYPE_INTRUSIVE(address, street, housenumber, postcode)
};
}
```
#### How do I convert third-party types? #### How do I convert third-party types?
@@ -1139,6 +1190,7 @@ Though it's 2020 already, the support for C++11 is still a bit sparse. Currently
- GCC 4.8 - 10.1 (and possibly later) - GCC 4.8 - 10.1 (and possibly later)
- Clang 3.4 - 10.0 (and possibly later) - Clang 3.4 - 10.0 (and possibly later)
- Apple Clang 9.1 - 12.0 (and possibly later)
- Intel C++ Compiler 17.0.2 (and possibly later) - Intel C++ Compiler 17.0.2 (and possibly later)
- Microsoft Visual C++ 2015 / Build Tools 14.0.25123.0 (and possibly later) - Microsoft Visual C++ 2015 / Build Tools 14.0.25123.0 (and possibly later)
- Microsoft Visual C++ 2017 / Build Tools 15.5.180.51428 (and possibly later) - Microsoft Visual C++ 2017 / Build Tools 15.5.180.51428 (and possibly later)
@@ -1184,6 +1236,8 @@ The following compilers are currently used in continuous integration at [Travis]
| Clang 6.0.1 (6.0.1-svn334776-1~exp1~20190309042707.121) | Ubuntu 14.04.5 LTS | Travis | | Clang 6.0.1 (6.0.1-svn334776-1~exp1~20190309042707.121) | Ubuntu 14.04.5 LTS | Travis |
| Clang 7.1.0 (7.1.0-svn353565-1~exp1~20190419134007.64) | Ubuntu 14.04.5 LTS | Travis | | Clang 7.1.0 (7.1.0-svn353565-1~exp1~20190419134007.64) | Ubuntu 14.04.5 LTS | Travis |
| Clang 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04) | Ubuntu 18.04.4 LTS | Travis | | Clang 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04) | Ubuntu 18.04.4 LTS | Travis |
| Clang 9.0.0 (x86_64-pc-windows-msvc) | Windows-10.0.17763 | GitHub Actions |
| Clang 10.0.0 (x86_64-pc-windows-msvc) | Windows-10.0.17763 | GitHub Actions |
| GCC 4.8.5 (Ubuntu 4.8.5-4ubuntu8~14.04.2) | Ubuntu 14.04.5 LTS | Travis | | GCC 4.8.5 (Ubuntu 4.8.5-4ubuntu8~14.04.2) | Ubuntu 14.04.5 LTS | Travis |
| GCC 4.9.4 (Ubuntu 4.9.4-2ubuntu1~14.04.1) | Ubuntu 14.04.5 LTS | Travis | | GCC 4.9.4 (Ubuntu 4.9.4-2ubuntu1~14.04.1) | Ubuntu 14.04.5 LTS | Travis |
| GCC 5.5.0 (Ubuntu 5.5.0-12ubuntu1~14.04) | Ubuntu 14.04.5 LTS | Travis | | GCC 5.5.0 (Ubuntu 5.5.0-12ubuntu1~14.04) | Ubuntu 14.04.5 LTS | Travis |
@@ -1508,7 +1562,7 @@ The library supports **Unicode input** as follows:
### Comments in JSON ### Comments in JSON
This library does not support comments. It does so for three reasons: This library does not support comments by default. It does so for three reasons:
1. Comments are not part of the [JSON specification](https://tools.ietf.org/html/rfc8259). You may argue that `//` or `/* */` are allowed in JavaScript, but JSON is not JavaScript. 1. Comments are not part of the [JSON specification](https://tools.ietf.org/html/rfc8259). You may argue that `//` or `/* */` are allowed in JavaScript, but JSON is not JavaScript.
2. This was not an oversight: Douglas Crockford [wrote on this](https://plus.google.com/118095276221607585885/posts/RK8qyGVaGSr) in May 2012: 2. This was not an oversight: Douglas Crockford [wrote on this](https://plus.google.com/118095276221607585885/posts/RK8qyGVaGSr) in May 2012:
@@ -1519,15 +1573,13 @@ This library does not support comments. It does so for three reasons:
3. It is dangerous for interoperability if some libraries would add comment support while others don't. Please check [The Harmful Consequences of the Robustness Principle](https://tools.ietf.org/html/draft-iab-protocol-maintenance-01) on this. 3. It is dangerous for interoperability if some libraries would add comment support while others don't. Please check [The Harmful Consequences of the Robustness Principle](https://tools.ietf.org/html/draft-iab-protocol-maintenance-01) on this.
This library will not support comments in the future. If you wish to use comments, I see three options: However, you can pass set parameter `ignore_comments` to true in the `parse` function to ignore `//` or `/* */` comments. Comments will then be treated as whitespace.
1. Strip comments before using this library.
2. Use a different JSON library with comment support.
3. Use a format that natively supports comments (e.g., YAML or JSON5).
### Order of object keys ### Order of object keys
By default, the library does not preserve the **insertion order of object elements**. This is standards-compliant, as the [JSON standard](https://tools.ietf.org/html/rfc8259.html) defines objects as "an unordered collection of zero or more name/value pairs". If you do want to preserve the insertion order, you can specialize the object type with containers like [`tsl::ordered_map`](https://github.com/Tessil/ordered-map) ([integration](https://github.com/nlohmann/json/issues/546#issuecomment-304447518)) or [`nlohmann::fifo_map`](https://github.com/nlohmann/fifo_map) ([integration](https://github.com/nlohmann/json/issues/485#issuecomment-333652309)). By default, the library does not preserve the **insertion order of object elements**. This is standards-compliant, as the [JSON standard](https://tools.ietf.org/html/rfc8259.html) defines objects as "an unordered collection of zero or more name/value pairs".
If you do want to preserve the insertion order, you can try the type [`nlohmann::ordered_json`](https://github.com/nlohmann/json/issues/2179). Alternatively, you can use a more sophisticated ordered map like [`tsl::ordered_map`](https://github.com/Tessil/ordered-map) ([integration](https://github.com/nlohmann/json/issues/546#issuecomment-304447518)) or [`nlohmann::fifo_map`](https://github.com/nlohmann/fifo_map) ([integration](https://github.com/nlohmann/json/issues/485#issuecomment-333652309)).
### Memory Release ### Memory Release
@@ -1540,7 +1592,7 @@ Here is a related issue [#1924](https://github.com/nlohmann/json/issues/1924).
### Further notes ### Further notes
- The code contains numerous debug **assertions** which can be switched off by defining the preprocessor macro `NDEBUG`, see the [documentation of `assert`](https://en.cppreference.com/w/cpp/error/assert). In particular, note [`operator[]`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a233b02b0839ef798942dd46157cc0fe6.html#a233b02b0839ef798942dd46157cc0fe6) implements **unchecked access** for const objects: If the given key is not present, the behavior is undefined (think of a dereferenced null pointer) and yields an [assertion failure](https://github.com/nlohmann/json/issues/289) if assertions are switched on. If you are not sure whether an element in an object exists, use checked access with the [`at()` function](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a73ae333487310e3302135189ce8ff5d8.html#a73ae333487310e3302135189ce8ff5d8). - The code contains numerous debug **assertions** which can be switched off by defining the preprocessor macro `NDEBUG`, see the [documentation of `assert`](https://en.cppreference.com/w/cpp/error/assert). In particular, note [`operator[]`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a233b02b0839ef798942dd46157cc0fe6.html#a233b02b0839ef798942dd46157cc0fe6) implements **unchecked access** for const objects: If the given key is not present, the behavior is undefined (think of a dereferenced null pointer) and yields an [assertion failure](https://github.com/nlohmann/json/issues/289) if assertions are switched on. If you are not sure whether an element in an object exists, use checked access with the [`at()` function](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a73ae333487310e3302135189ce8ff5d8.html#a73ae333487310e3302135189ce8ff5d8). Furthermore, you can define `JSON_ASSERT(x)` to replace calls to `assert(x)`.
- As the exact type of a number is not defined in the [JSON specification](https://tools.ietf.org/html/rfc8259.html), this library tries to choose the best fitting C++ number type automatically. As a result, the type `double` may be used to store numbers which may yield [**floating-point exceptions**](https://github.com/nlohmann/json/issues/181) in certain rare situations if floating-point exceptions have been unmasked in the calling code. These exceptions are not caused by the library and need to be fixed in the calling code, such as by re-masking the exceptions prior to calling library functions. - As the exact type of a number is not defined in the [JSON specification](https://tools.ietf.org/html/rfc8259.html), this library tries to choose the best fitting C++ number type automatically. As a result, the type `double` may be used to store numbers which may yield [**floating-point exceptions**](https://github.com/nlohmann/json/issues/181) in certain rare situations if floating-point exceptions have been unmasked in the calling code. These exceptions are not caused by the library and need to be fixed in the calling code, such as by re-masking the exceptions prior to calling library functions.
- The code can be compiled without C++ **runtime type identification** features; that is, you can use the `-fno-rtti` compiler flag. - The code can be compiled without C++ **runtime type identification** features; that is, you can use the `-fno-rtti` compiler flag.
- **Exceptions** are used widely within the library. They can, however, be switched off with either using the compiler flag `-fno-exceptions` or by defining the symbol `JSON_NOEXCEPTION`. In this case, exceptions are replaced by `abort()` calls. You can further control this behavior by defining `JSON_THROW_USER´` (overriding `throw`), `JSON_TRY_USER` (overriding `try`), and `JSON_CATCH_USER` (overriding `catch`). Note that `JSON_THROW_USER` should leave the current scope (e.g., by throwing or aborting), as continuing after it may yield undefined behavior. - **Exceptions** are used widely within the library. They can, however, be switched off with either using the compiler flag `-fno-exceptions` or by defining the symbol `JSON_NOEXCEPTION`. In this case, exceptions are replaced by `abort()` calls. You can further control this behavior by defining `JSON_THROW_USER´` (overriding `throw`), `JSON_TRY_USER` (overriding `try`), and `JSON_CATCH_USER` (overriding `catch`). Note that `JSON_THROW_USER` should leave the current scope (e.g., by throwing or aborting), as continuing after it may yield undefined behavior.
@@ -1557,4 +1609,6 @@ $ cmake --build .
$ ctest --output-on-failure $ ctest --output-on-failure
``` ```
For more information, have a look at the file [.travis.yml](https://github.com/nlohmann/json/blob/master/.travis.yml). Note that during the `ctest` stage, several JSON test files are downloaded from an [external repository](https://github.com/nlohmann/json_test_data). If policies forbid downloading artifacts during testing, you can download the files yourself and pass the directory with the test files via `-DJSON_TestDataDirectory=path` to CMake. Then, no Internet connectivity is required. See [issue #2189](https://github.com/nlohmann/json/issues/2189) for more information.
In case you have downloaded the library rather than checked out the code via Git, test `cmake_fetch_content_configure`. Please execute `ctest -LE git_required` to skip these tests. See [issue #2189](https://github.com/nlohmann/json/issues/2189) for more information.
+9 -4
View File
@@ -1,17 +1,22 @@
find_package(Git)
set(JSON_TEST_DATA_URL https://github.com/nlohmann/json_test_data) set(JSON_TEST_DATA_URL https://github.com/nlohmann/json_test_data)
set(JSON_TEST_DATA_VERSION 2.0.0) set(JSON_TEST_DATA_VERSION 3.0.0)
# if variable is set, use test data from given directory rather than downloading them
if(JSON_TestDataDirectory)
message(STATUS "Using test data in ${JSON_TestDataDirectory}.")
add_custom_target(download_test_data)
file(WRITE ${CMAKE_BINARY_DIR}/include/test_data.hpp "#define TEST_DATA_DIRECTORY \"${JSON_TestDataDirectory}\"\n")
else()
find_package(Git)
# target to download test data # target to download test data
add_custom_target(download_test_data add_custom_target(download_test_data
COMMAND test -d json_test_data || ${GIT_EXECUTABLE} clone -c advice.detachedHead=false --branch v${JSON_TEST_DATA_VERSION} ${JSON_TEST_DATA_URL}.git --quiet --depth 1 COMMAND test -d json_test_data || ${GIT_EXECUTABLE} clone -c advice.detachedHead=false --branch v${JSON_TEST_DATA_VERSION} ${JSON_TEST_DATA_URL}.git --quiet --depth 1
COMMENT "Downloading test data from ${JSON_TEST_DATA_URL} (v${JSON_TEST_DATA_VERSION})" COMMENT "Downloading test data from ${JSON_TEST_DATA_URL} (v${JSON_TEST_DATA_VERSION})"
WORKING_DIRECTORY ${CMAKE_BINARY_DIR} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
) )
# create a header with the path to the downloaded test data # create a header with the path to the downloaded test data
file(WRITE ${CMAKE_BINARY_DIR}/include/test_data.hpp "#define TEST_DATA_DIRECTORY \"${CMAKE_BINARY_DIR}/json_test_data\"\n") file(WRITE ${CMAKE_BINARY_DIR}/include/test_data.hpp "#define TEST_DATA_DIRECTORY \"${CMAKE_BINARY_DIR}/json_test_data\"\n")
endif()
# determine the operating system (for debug and support purposes) # determine the operating system (for debug and support purposes)
find_program(UNAME_COMMAND uname) find_program(UNAME_COMMAND uname)
+4
View File
@@ -0,0 +1,4 @@
Name: ${PROJECT_NAME}
Description: JSON for Modern C++
Version: ${PROJECT_VERSION}
Cflags: -I${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}
@@ -81,6 +81,43 @@ Some important things:
* You do not need to add serializers or deserializers for STL types like `std::vector`: the library already implements these. * You do not need to add serializers or deserializers for STL types like `std::vector`: the library already implements these.
## Simplify your life with macros
If you just want to serialize/deserialize some structs, the `to_json`/`from_json` functions can be a lot of boilerplate.
There are two macros to make your life easier as long as you (1) want to use a JSON object as serialization and (2) want to use the member variable names as object keys in that object:
- `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(name, member1, member2, ...)` is to be defined inside of the namespace of the class/struct to create code for.
- `NLOHMANN_DEFINE_TYPE_INTRUSIVE(name, member1, member2, ...)` is to be defined inside of the class/struct to create code for. This macro can also access private members.
In both macros, the first parameter is the name of the class/struct, and all remaining parameters name the members.
??? example
The `to_json`/`from_json` functions for the `person` struct above can be created with:
```cpp
namespace ns {
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(person, name, address, age)
}
```
Here is an example with private members, where `NLOHMANN_DEFINE_TYPE_INTRUSIVE` is needed:
```cpp
namespace ns {
class address {
private:
std::string street;
int housenumber;
int postcode;
public:
NLOHMANN_DEFINE_TYPE_INTRUSIVE(address, street, housenumber, postcode)
};
}
```
## How do I convert third-party types? ## How do I convert third-party types?
This requires a bit more advanced technique. But first, let's see how this conversion mechanism works: This requires a bit more advanced technique. But first, let's see how this conversion mechanism works:
@@ -31,7 +31,8 @@ number_unsigned | 128..255 | uint 8 | 0xCC
number_unsigned | 256..65535 | uint 16 | 0xCD number_unsigned | 256..65535 | uint 16 | 0xCD
number_unsigned | 65536..4294967295 | uint 32 | 0xCE number_unsigned | 65536..4294967295 | uint 32 | 0xCE
number_unsigned | 4294967296..18446744073709551615 | uint 64 | 0xCF number_unsigned | 4294967296..18446744073709551615 | uint 64 | 0xCF
number_float | *any value* | float 64 | 0xCB number_float | *any value representable by a float* | float 32 | 0xCA
number_float | *any value NOT representable by a float* | float 64 | 0xCB
string | *length*: 0..31 | fixstr | 0xA0..0xBF string | *length*: 0..31 | fixstr | 0xA0..0xBF
string | *length*: 32..255 | str 8 | 0xD9 string | *length*: 32..255 | str 8 | 0xD9
string | *length*: 256..65535 | str 16 | 0xDA string | *length*: 256..65535 | str 16 | 0xDA
@@ -61,10 +62,6 @@ binary | *size*: 65536..4294967295 | bin 32 | 0xC6
- arrays with more than 4294967295 elements - arrays with more than 4294967295 elements
- objects with more than 4294967295 elements - objects with more than 4294967295 elements
!!! info "Unused MessagePack types"
The following MessagePack types are not used in the conversion: float 32 (0xCA)
!!! info "NaN/infinity handling" !!! info "NaN/infinity handling"
If NaN or Infinity are stored inside a JSON number, they are serialized properly. function which serializes NaN or Infinity to `null`. If NaN or Infinity are stored inside a JSON number, they are serialized properly. function which serializes NaN or Infinity to `null`.
+55
View File
@@ -0,0 +1,55 @@
# Supported Macros
Some aspects of the library can be configured by defining preprocessor macros before including the `json.hpp` header.
## `JSON_CATCH_USER(exception)`
This macro overrides `#!cpp catch` calls inside the library. The argument is the type of the exception to catch. As of version 3.8.0, the library only catches `std::out_of_range` exceptions internally to rethrow them as [`json::out_of_range`](../home/exceptions.md#out-of-range) exceptions. The macro is always followed by a scope.
See [Switch off exceptions](../home/exceptions.md#switch-off-exceptions) for an example.
## `JSON_NOEXCEPTION`
Exceptions can be switched off by defining the symbol `JSON_NOEXCEPTION`.
When defining `JSON_NOEXCEPTION`, `#!cpp try` is replaced by `#!cpp if (true)`,
`#!cpp catch` is replaced by `#!cpp if (false)`, and `#!cpp throw` is replaced by `#!cpp std::abort()`.
The same effect is achieved by setting the compiler flag `-fno-exceptions`.
## `JSON_SKIP_UNSUPPORTED_COMPILER_CHECK`
When defined, the library will not create a compile error when a known unsupported compiler is detected. This allows to use the library with compilers that do not fully support C++11 and may only work if unsupported features are not used.
## `JSON_THROW_USER(exception)`
This macro overrides `#!cpp throw` calls inside the library. The argument is the exception to be thrown. Note that `JSON_THROW_USER` should leave the current scope (e.g., by throwing or aborting), as continuing after it may yield undefined behavior.
See [Switch off exceptions](../home/exceptions.md#switch-off-exceptions) for an example.
## `JSON_TRY_USER`
This macro overrides `#!cpp try` calls inside the library. It has no arguments and is always followed by a scope.
See [Switch off exceptions](../home/exceptions.md#switch-off-exceptions) for an example.
## `NLOHMANN_DEFINE_TYPE_INTRUSIVE(type, member...)`
This macro can be used to simplify the serialization/deserialization of types if (1) want to use a JSON object as serialization and (2) want to use the member variable names as object keys in that object.
The macro is to be defined inside of the class/struct to create code for. Unlike [`NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE`](#nlohmann_define_type_non_intrusivetype-member), it can access private members.
The first parameter is the name of the class/struct, and all remaining parameters name the members.
See [Simplify your life with macros](arbitrary_types.md#simplify-your-life-with-macros) for an example.
## `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(type, member...)`
This macro can be used to simplify the serialization/deserialization of types if (1) want to use a JSON object as serialization and (2) want to use the member variable names as object keys in that object.
The macro is to be defined inside of the namespace of the class/struct to create code for. Private members cannot be accessed. Use [`NLOHMANN_DEFINE_TYPE_INTRUSIVE`](#nlohmann_define_type_intrusivetype-member) in these scenarios.
The first parameter is the name of the class/struct, and all remaining parameters name the members.
See [Simplify your life with macros](arbitrary_types.md#simplify-your-life-with-macros) for an example.
## `NLOHMANN_JSON_SERIALIZE_ENUM(type, ...)`
This macro simplifies the serialization/deserialization of enum types. See [Specializing enum conversion](enum_conversion.md) for more information.
+18
View File
@@ -32,6 +32,24 @@ Exceptions are used widely within the library. They can, however, be switched of
Note that `JSON_THROW_USER` should leave the current scope (e.g., by throwing or aborting), as continuing after it may yield undefined behavior. Note that `JSON_THROW_USER` should leave the current scope (e.g., by throwing or aborting), as continuing after it may yield undefined behavior.
??? example
The code below switches off exceptions and creates a log entry with a detailed error message in case of errors.
```cpp
#include <iostream>
#define JSON_TRY_USER if(true)
#define JSON_CATCH_USER(exception) if(false)
#define JSON_THROW_USER(exception) \
{std::clog << "Error in " << __FILE__ << ":" << __LINE__ \
<< " (function " << __FUNCTION__ << ") - " \
<< (exception).what() << std::endl; \
std::abort();}
#include <nlohmann/json.hpp>
```
## Parse errors ## Parse errors
This exception is thrown by the library when a parse error occurs. Parse errors This exception is thrown by the library when a parse error occurs. Parse errors
+1
View File
@@ -49,6 +49,7 @@ nav:
- features/json_patch.md - features/json_patch.md
- features/merge_patch.md - features/merge_patch.md
- features/enum_conversion.md - features/enum_conversion.md
- features/macros.md
- Parsing: - Parsing:
- features/parsing/index.md - features/parsing/index.md
- features/parsing/parse_exceptions.md - features/parsing/parse_exceptions.md
@@ -1,8 +0,0 @@
#pragma once
// Header <ciso646> is removed in C++20.
// See <https://github.com/nlohmann/json/issues/2089> for more information.
#if __cplusplus <= 201703L
#include <ciso646> // and, not, or
#endif
@@ -12,7 +12,6 @@
#include <utility> // pair, declval #include <utility> // pair, declval
#include <valarray> // valarray #include <valarray> // valarray
#include <nlohmann/detail/boolean_operators.hpp>
#include <nlohmann/detail/exceptions.hpp> #include <nlohmann/detail/exceptions.hpp>
#include <nlohmann/detail/macro_scope.hpp> #include <nlohmann/detail/macro_scope.hpp>
#include <nlohmann/detail/meta/cpp_future.hpp> #include <nlohmann/detail/meta/cpp_future.hpp>
@@ -26,7 +25,7 @@ namespace detail
template<typename BasicJsonType> template<typename BasicJsonType>
void from_json(const BasicJsonType& j, typename std::nullptr_t& n) void from_json(const BasicJsonType& j, typename std::nullptr_t& n)
{ {
if (JSON_HEDLEY_UNLIKELY(not j.is_null())) if (JSON_HEDLEY_UNLIKELY(!j.is_null()))
{ {
JSON_THROW(type_error::create(302, "type must be null, but is " + std::string(j.type_name()))); JSON_THROW(type_error::create(302, "type must be null, but is " + std::string(j.type_name())));
} }
@@ -35,8 +34,8 @@ void from_json(const BasicJsonType& j, typename std::nullptr_t& n)
// overloads for basic_json template parameters // overloads for basic_json template parameters
template < typename BasicJsonType, typename ArithmeticType, template < typename BasicJsonType, typename ArithmeticType,
enable_if_t<std::is_arithmetic<ArithmeticType>::value and enable_if_t < (std::is_arithmetic<ArithmeticType>::value || is_128_bit_integral<ArithmeticType>::value)&&
not std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value, !std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,
int > = 0 > int > = 0 >
void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val) void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val)
{ {
@@ -66,7 +65,7 @@ void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val)
template<typename BasicJsonType> template<typename BasicJsonType>
void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b) void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b)
{ {
if (JSON_HEDLEY_UNLIKELY(not j.is_boolean())) if (JSON_HEDLEY_UNLIKELY(!j.is_boolean()))
{ {
JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(j.type_name()))); JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(j.type_name())));
} }
@@ -76,7 +75,7 @@ void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b)
template<typename BasicJsonType> template<typename BasicJsonType>
void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s) void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s)
{ {
if (JSON_HEDLEY_UNLIKELY(not j.is_string())) if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
{ {
JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()))); JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name())));
} }
@@ -86,13 +85,13 @@ void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s)
template < template <
typename BasicJsonType, typename ConstructibleStringType, typename BasicJsonType, typename ConstructibleStringType,
enable_if_t < enable_if_t <
is_constructible_string_type<BasicJsonType, ConstructibleStringType>::value and is_constructible_string_type<BasicJsonType, ConstructibleStringType>::value&&
not std::is_same<typename BasicJsonType::string_t, !std::is_same<typename BasicJsonType::string_t,
ConstructibleStringType>::value, ConstructibleStringType>::value,
int > = 0 > int > = 0 >
void from_json(const BasicJsonType& j, ConstructibleStringType& s) void from_json(const BasicJsonType& j, ConstructibleStringType& s)
{ {
if (JSON_HEDLEY_UNLIKELY(not j.is_string())) if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
{ {
JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()))); JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name())));
} }
@@ -132,7 +131,7 @@ template<typename BasicJsonType, typename T, typename Allocator,
enable_if_t<std::is_convertible<BasicJsonType, T>::value, int> = 0> enable_if_t<std::is_convertible<BasicJsonType, T>::value, int> = 0>
void from_json(const BasicJsonType& j, std::forward_list<T, Allocator>& l) void from_json(const BasicJsonType& j, std::forward_list<T, Allocator>& l)
{ {
if (JSON_HEDLEY_UNLIKELY(not j.is_array())) if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
{ {
JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name())));
} }
@@ -149,7 +148,7 @@ template<typename BasicJsonType, typename T,
enable_if_t<std::is_convertible<BasicJsonType, T>::value, int> = 0> enable_if_t<std::is_convertible<BasicJsonType, T>::value, int> = 0>
void from_json(const BasicJsonType& j, std::valarray<T>& l) void from_json(const BasicJsonType& j, std::valarray<T>& l)
{ {
if (JSON_HEDLEY_UNLIKELY(not j.is_array())) if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
{ {
JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name())));
} }
@@ -225,18 +224,18 @@ void from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr,
template < typename BasicJsonType, typename ConstructibleArrayType, template < typename BasicJsonType, typename ConstructibleArrayType,
enable_if_t < enable_if_t <
is_constructible_array_type<BasicJsonType, ConstructibleArrayType>::value and is_constructible_array_type<BasicJsonType, ConstructibleArrayType>::value&&
not is_constructible_object_type<BasicJsonType, ConstructibleArrayType>::value and !is_constructible_object_type<BasicJsonType, ConstructibleArrayType>::value&&
not is_constructible_string_type<BasicJsonType, ConstructibleArrayType>::value and !is_constructible_string_type<BasicJsonType, ConstructibleArrayType>::value&&
not std::is_same<ConstructibleArrayType, typename BasicJsonType::binary_t>::value and !std::is_same<ConstructibleArrayType, typename BasicJsonType::binary_t>::value&&
not is_basic_json<ConstructibleArrayType>::value, !is_basic_json<ConstructibleArrayType>::value,
int > = 0 > int > = 0 >
auto from_json(const BasicJsonType& j, ConstructibleArrayType& arr) auto from_json(const BasicJsonType& j, ConstructibleArrayType& arr)
-> decltype(from_json_array_impl(j, arr, priority_tag<3> {}), -> decltype(from_json_array_impl(j, arr, priority_tag<3> {}),
j.template get<typename ConstructibleArrayType::value_type>(), j.template get<typename ConstructibleArrayType::value_type>(),
void()) void())
{ {
if (JSON_HEDLEY_UNLIKELY(not j.is_array())) if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
{ {
JSON_THROW(type_error::create(302, "type must be array, but is " + JSON_THROW(type_error::create(302, "type must be array, but is " +
std::string(j.type_name()))); std::string(j.type_name())));
@@ -248,7 +247,7 @@ void())
template<typename BasicJsonType> template<typename BasicJsonType>
void from_json(const BasicJsonType& j, typename BasicJsonType::binary_t& bin) void from_json(const BasicJsonType& j, typename BasicJsonType::binary_t& bin)
{ {
if (JSON_HEDLEY_UNLIKELY(not j.is_binary())) if (JSON_HEDLEY_UNLIKELY(!j.is_binary()))
{ {
JSON_THROW(type_error::create(302, "type must be binary, but is " + std::string(j.type_name()))); JSON_THROW(type_error::create(302, "type must be binary, but is " + std::string(j.type_name())));
} }
@@ -260,7 +259,7 @@ template<typename BasicJsonType, typename ConstructibleObjectType,
enable_if_t<is_constructible_object_type<BasicJsonType, ConstructibleObjectType>::value, int> = 0> enable_if_t<is_constructible_object_type<BasicJsonType, ConstructibleObjectType>::value, int> = 0>
void from_json(const BasicJsonType& j, ConstructibleObjectType& obj) void from_json(const BasicJsonType& j, ConstructibleObjectType& obj)
{ {
if (JSON_HEDLEY_UNLIKELY(not j.is_object())) if (JSON_HEDLEY_UNLIKELY(!j.is_object()))
{ {
JSON_THROW(type_error::create(302, "type must be object, but is " + std::string(j.type_name()))); JSON_THROW(type_error::create(302, "type must be object, but is " + std::string(j.type_name())));
} }
@@ -284,11 +283,11 @@ void from_json(const BasicJsonType& j, ConstructibleObjectType& obj)
// an arithmetic type? // an arithmetic type?
template < typename BasicJsonType, typename ArithmeticType, template < typename BasicJsonType, typename ArithmeticType,
enable_if_t < enable_if_t <
std::is_arithmetic<ArithmeticType>::value and std::is_arithmetic<ArithmeticType>::value&&
not std::is_same<ArithmeticType, typename BasicJsonType::number_unsigned_t>::value and !std::is_same<ArithmeticType, typename BasicJsonType::number_unsigned_t>::value&&
not std::is_same<ArithmeticType, typename BasicJsonType::number_integer_t>::value and !std::is_same<ArithmeticType, typename BasicJsonType::number_integer_t>::value&&
not std::is_same<ArithmeticType, typename BasicJsonType::number_float_t>::value and !std::is_same<ArithmeticType, typename BasicJsonType::number_float_t>::value&&
not std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value, !std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,
int > = 0 > int > = 0 >
void from_json(const BasicJsonType& j, ArithmeticType& val) void from_json(const BasicJsonType& j, ArithmeticType& val)
{ {
@@ -339,18 +338,18 @@ void from_json(const BasicJsonType& j, std::tuple<Args...>& t)
} }
template < typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator, template < typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator,
typename = enable_if_t<not std::is_constructible< typename = enable_if_t < !std::is_constructible <
typename BasicJsonType::string_t, Key >::value >> typename BasicJsonType::string_t, Key >::value >>
void from_json(const BasicJsonType& j, std::map<Key, Value, Compare, Allocator>& m) void from_json(const BasicJsonType& j, std::map<Key, Value, Compare, Allocator>& m)
{ {
if (JSON_HEDLEY_UNLIKELY(not j.is_array())) if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
{ {
JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name())));
} }
m.clear(); m.clear();
for (const auto& p : j) for (const auto& p : j)
{ {
if (JSON_HEDLEY_UNLIKELY(not p.is_array())) if (JSON_HEDLEY_UNLIKELY(!p.is_array()))
{ {
JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(p.type_name()))); JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(p.type_name())));
} }
@@ -359,18 +358,18 @@ void from_json(const BasicJsonType& j, std::map<Key, Value, Compare, Allocator>&
} }
template < typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator, template < typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator,
typename = enable_if_t<not std::is_constructible< typename = enable_if_t < !std::is_constructible <
typename BasicJsonType::string_t, Key >::value >> typename BasicJsonType::string_t, Key >::value >>
void from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyEqual, Allocator>& m) void from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyEqual, Allocator>& m)
{ {
if (JSON_HEDLEY_UNLIKELY(not j.is_array())) if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
{ {
JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name())));
} }
m.clear(); m.clear();
for (const auto& p : j) for (const auto& p : j)
{ {
if (JSON_HEDLEY_UNLIKELY(not p.is_array())) if (JSON_HEDLEY_UNLIKELY(!p.is_array()))
{ {
JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(p.type_name()))); JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(p.type_name())));
} }
@@ -1,14 +1,12 @@
#pragma once #pragma once
#include <array> // array #include <array> // array
#include <cassert> // assert
#include <cmath> // signbit, isfinite #include <cmath> // signbit, isfinite
#include <cstdint> // intN_t, uintN_t #include <cstdint> // intN_t, uintN_t
#include <cstring> // memcpy, memmove #include <cstring> // memcpy, memmove
#include <limits> // numeric_limits #include <limits> // numeric_limits
#include <type_traits> // conditional #include <type_traits> // conditional
#include <nlohmann/detail/boolean_operators.hpp>
#include <nlohmann/detail/macro_scope.hpp> #include <nlohmann/detail/macro_scope.hpp>
namespace nlohmann namespace nlohmann
@@ -63,8 +61,8 @@ struct diyfp // f * 2^e
*/ */
static diyfp sub(const diyfp& x, const diyfp& y) noexcept static diyfp sub(const diyfp& x, const diyfp& y) noexcept
{ {
assert(x.e == y.e); JSON_ASSERT(x.e == y.e);
assert(x.f >= y.f); JSON_ASSERT(x.f >= y.f);
return {x.f - y.f, x.e}; return {x.f - y.f, x.e};
} }
@@ -140,7 +138,7 @@ struct diyfp // f * 2^e
*/ */
static diyfp normalize(diyfp x) noexcept static diyfp normalize(diyfp x) noexcept
{ {
assert(x.f != 0); JSON_ASSERT(x.f != 0);
while ((x.f >> 63u) == 0) while ((x.f >> 63u) == 0)
{ {
@@ -159,8 +157,8 @@ struct diyfp // f * 2^e
{ {
const int delta = x.e - target_exponent; const int delta = x.e - target_exponent;
assert(delta >= 0); JSON_ASSERT(delta >= 0);
assert(((x.f << delta) >> delta) == x.f); JSON_ASSERT(((x.f << delta) >> delta) == x.f);
return {x.f << delta, target_exponent}; return {x.f << delta, target_exponent};
} }
@@ -182,8 +180,8 @@ boundaries.
template<typename FloatType> template<typename FloatType>
boundaries compute_boundaries(FloatType value) boundaries compute_boundaries(FloatType value)
{ {
assert(std::isfinite(value)); JSON_ASSERT(std::isfinite(value));
assert(value > 0); JSON_ASSERT(value > 0);
// Convert the IEEE representation into a diyfp. // Convert the IEEE representation into a diyfp.
// //
@@ -232,7 +230,7 @@ boundaries compute_boundaries(FloatType value)
// -----------------+------+------+-------------+-------------+--- (B) // -----------------+------+------+-------------+-------------+--- (B)
// v- m- v m+ v+ // v- m- v m+ v+
const bool lower_boundary_is_closer = F == 0 and E > 1; const bool lower_boundary_is_closer = F == 0 && E > 1;
const diyfp m_plus = diyfp(2 * v.f + 1, v.e - 1); const diyfp m_plus = diyfp(2 * v.f + 1, v.e - 1);
const diyfp m_minus = lower_boundary_is_closer const diyfp m_minus = lower_boundary_is_closer
? diyfp(4 * v.f - 1, v.e - 2) // (B) ? diyfp(4 * v.f - 1, v.e - 2) // (B)
@@ -463,18 +461,18 @@ inline cached_power get_cached_power_for_binary_exponent(int e)
// k = ceil((kAlpha - e - 1) * 0.30102999566398114) // k = ceil((kAlpha - e - 1) * 0.30102999566398114)
// for |e| <= 1500, but doesn't require floating-point operations. // for |e| <= 1500, but doesn't require floating-point operations.
// NB: log_10(2) ~= 78913 / 2^18 // NB: log_10(2) ~= 78913 / 2^18
assert(e >= -1500); JSON_ASSERT(e >= -1500);
assert(e <= 1500); JSON_ASSERT(e <= 1500);
const int f = kAlpha - e - 1; const int f = kAlpha - e - 1;
const int k = (f * 78913) / (1 << 18) + static_cast<int>(f > 0); const int k = (f * 78913) / (1 << 18) + static_cast<int>(f > 0);
const int index = (-kCachedPowersMinDecExp + k + (kCachedPowersDecStep - 1)) / kCachedPowersDecStep; const int index = (-kCachedPowersMinDecExp + k + (kCachedPowersDecStep - 1)) / kCachedPowersDecStep;
assert(index >= 0); JSON_ASSERT(index >= 0);
assert(static_cast<std::size_t>(index) < kCachedPowers.size()); JSON_ASSERT(static_cast<std::size_t>(index) < kCachedPowers.size());
const cached_power cached = kCachedPowers[static_cast<std::size_t>(index)]; const cached_power cached = kCachedPowers[static_cast<std::size_t>(index)];
assert(kAlpha <= cached.e + e + 64); JSON_ASSERT(kAlpha <= cached.e + e + 64);
assert(kGamma >= cached.e + e + 64); JSON_ASSERT(kGamma >= cached.e + e + 64);
return cached; return cached;
} }
@@ -542,10 +540,10 @@ inline int find_largest_pow10(const std::uint32_t n, std::uint32_t& pow10)
inline void grisu2_round(char* buf, int len, std::uint64_t dist, std::uint64_t delta, inline void grisu2_round(char* buf, int len, std::uint64_t dist, std::uint64_t delta,
std::uint64_t rest, std::uint64_t ten_k) std::uint64_t rest, std::uint64_t ten_k)
{ {
assert(len >= 1); JSON_ASSERT(len >= 1);
assert(dist <= delta); JSON_ASSERT(dist <= delta);
assert(rest <= delta); JSON_ASSERT(rest <= delta);
assert(ten_k > 0); JSON_ASSERT(ten_k > 0);
// <--------------------------- delta ----> // <--------------------------- delta ---->
// <---- dist ---------> // <---- dist --------->
@@ -567,10 +565,10 @@ inline void grisu2_round(char* buf, int len, std::uint64_t dist, std::uint64_t d
// integer arithmetic. // integer arithmetic.
while (rest < dist while (rest < dist
and delta - rest >= ten_k && delta - rest >= ten_k
and (rest + ten_k < dist or dist - rest > rest + ten_k - dist)) && (rest + ten_k < dist || dist - rest > rest + ten_k - dist))
{ {
assert(buf[len - 1] != '0'); JSON_ASSERT(buf[len - 1] != '0');
buf[len - 1]--; buf[len - 1]--;
rest += ten_k; rest += ten_k;
} }
@@ -598,8 +596,8 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,
// Grisu2 generates the digits of M+ from left to right and stops as soon as // Grisu2 generates the digits of M+ from left to right and stops as soon as
// V is in [M-,M+]. // V is in [M-,M+].
assert(M_plus.e >= kAlpha); JSON_ASSERT(M_plus.e >= kAlpha);
assert(M_plus.e <= kGamma); JSON_ASSERT(M_plus.e <= kGamma);
std::uint64_t delta = diyfp::sub(M_plus, M_minus).f; // (significand of (M+ - M-), implicit exponent is e) std::uint64_t delta = diyfp::sub(M_plus, M_minus).f; // (significand of (M+ - M-), implicit exponent is e)
std::uint64_t dist = diyfp::sub(M_plus, w ).f; // (significand of (M+ - w ), implicit exponent is e) std::uint64_t dist = diyfp::sub(M_plus, w ).f; // (significand of (M+ - w ), implicit exponent is e)
@@ -620,7 +618,7 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,
// //
// Generate the digits of the integral part p1 = d[n-1]...d[1]d[0] // Generate the digits of the integral part p1 = d[n-1]...d[1]d[0]
assert(p1 > 0); JSON_ASSERT(p1 > 0);
std::uint32_t pow10; std::uint32_t pow10;
const int k = find_largest_pow10(p1, pow10); const int k = find_largest_pow10(p1, pow10);
@@ -656,7 +654,7 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,
// M+ = buffer * 10^n + (d * 10^(n-1) + r) + p2 * 2^e // M+ = buffer * 10^n + (d * 10^(n-1) + r) + p2 * 2^e
// = (buffer * 10 + d) * 10^(n-1) + (r + p2 * 2^e) // = (buffer * 10 + d) * 10^(n-1) + (r + p2 * 2^e)
// //
assert(d <= 9); JSON_ASSERT(d <= 9);
buffer[length++] = static_cast<char>('0' + d); // buffer := buffer * 10 + d buffer[length++] = static_cast<char>('0' + d); // buffer := buffer * 10 + d
// //
// M+ = buffer * 10^(n-1) + (r + p2 * 2^e) // M+ = buffer * 10^(n-1) + (r + p2 * 2^e)
@@ -743,7 +741,7 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,
// //
// and stop as soon as 10^-m * r * 2^e <= delta * 2^e // and stop as soon as 10^-m * r * 2^e <= delta * 2^e
assert(p2 > delta); JSON_ASSERT(p2 > delta);
int m = 0; int m = 0;
for (;;) for (;;)
@@ -754,7 +752,7 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,
// = buffer * 10^-m + 10^-m * (1/10 * (10 * p2) ) * 2^e // = buffer * 10^-m + 10^-m * (1/10 * (10 * p2) ) * 2^e
// = buffer * 10^-m + 10^-m * (1/10 * ((10*p2 div 2^-e) * 2^-e + (10*p2 mod 2^-e)) * 2^e // = buffer * 10^-m + 10^-m * (1/10 * ((10*p2 div 2^-e) * 2^-e + (10*p2 mod 2^-e)) * 2^e
// //
assert(p2 <= (std::numeric_limits<std::uint64_t>::max)() / 10); JSON_ASSERT(p2 <= (std::numeric_limits<std::uint64_t>::max)() / 10);
p2 *= 10; p2 *= 10;
const std::uint64_t d = p2 >> -one.e; // d = (10 * p2) div 2^-e const std::uint64_t d = p2 >> -one.e; // d = (10 * p2) div 2^-e
const std::uint64_t r = p2 & (one.f - 1); // r = (10 * p2) mod 2^-e const std::uint64_t r = p2 & (one.f - 1); // r = (10 * p2) mod 2^-e
@@ -763,7 +761,7 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,
// = buffer * 10^-m + 10^-m * (1/10 * (d + r * 2^e)) // = buffer * 10^-m + 10^-m * (1/10 * (d + r * 2^e))
// = (buffer * 10 + d) * 10^(-m-1) + 10^(-m-1) * r * 2^e // = (buffer * 10 + d) * 10^(-m-1) + 10^(-m-1) * r * 2^e
// //
assert(d <= 9); JSON_ASSERT(d <= 9);
buffer[length++] = static_cast<char>('0' + d); // buffer := buffer * 10 + d buffer[length++] = static_cast<char>('0' + d); // buffer := buffer * 10 + d
// //
// M+ = buffer * 10^(-m-1) + 10^(-m-1) * r * 2^e // M+ = buffer * 10^(-m-1) + 10^(-m-1) * r * 2^e
@@ -824,8 +822,8 @@ JSON_HEDLEY_NON_NULL(1)
inline void grisu2(char* buf, int& len, int& decimal_exponent, inline void grisu2(char* buf, int& len, int& decimal_exponent,
diyfp m_minus, diyfp v, diyfp m_plus) diyfp m_minus, diyfp v, diyfp m_plus)
{ {
assert(m_plus.e == m_minus.e); JSON_ASSERT(m_plus.e == m_minus.e);
assert(m_plus.e == v.e); JSON_ASSERT(m_plus.e == v.e);
// --------(-----------------------+-----------------------)-------- (A) // --------(-----------------------+-----------------------)-------- (A)
// m- v m+ // m- v m+
@@ -886,8 +884,8 @@ void grisu2(char* buf, int& len, int& decimal_exponent, FloatType value)
static_assert(diyfp::kPrecision >= std::numeric_limits<FloatType>::digits + 3, static_assert(diyfp::kPrecision >= std::numeric_limits<FloatType>::digits + 3,
"internal error: not enough precision"); "internal error: not enough precision");
assert(std::isfinite(value)); JSON_ASSERT(std::isfinite(value));
assert(value > 0); JSON_ASSERT(value > 0);
// If the neighbors (and boundaries) of 'value' are always computed for double-precision // If the neighbors (and boundaries) of 'value' are always computed for double-precision
// numbers, all float's can be recovered using strtod (and strtof). However, the resulting // numbers, all float's can be recovered using strtod (and strtof). However, the resulting
@@ -923,8 +921,8 @@ JSON_HEDLEY_NON_NULL(1)
JSON_HEDLEY_RETURNS_NON_NULL JSON_HEDLEY_RETURNS_NON_NULL
inline char* append_exponent(char* buf, int e) inline char* append_exponent(char* buf, int e)
{ {
assert(e > -1000); JSON_ASSERT(e > -1000);
assert(e < 1000); JSON_ASSERT(e < 1000);
if (e < 0) if (e < 0)
{ {
@@ -976,8 +974,8 @@ JSON_HEDLEY_RETURNS_NON_NULL
inline char* format_buffer(char* buf, int len, int decimal_exponent, inline char* format_buffer(char* buf, int len, int decimal_exponent,
int min_exp, int max_exp) int min_exp, int max_exp)
{ {
assert(min_exp < 0); JSON_ASSERT(min_exp < 0);
assert(max_exp > 0); JSON_ASSERT(max_exp > 0);
const int k = len; const int k = len;
const int n = len + decimal_exponent; const int n = len + decimal_exponent;
@@ -986,7 +984,7 @@ inline char* format_buffer(char* buf, int len, int decimal_exponent,
// k is the length of the buffer (number of decimal digits) // k is the length of the buffer (number of decimal digits)
// n is the position of the decimal point relative to the start of the buffer. // n is the position of the decimal point relative to the start of the buffer.
if (k <= n and n <= max_exp) if (k <= n && n <= max_exp)
{ {
// digits[000] // digits[000]
// len <= max_exp + 2 // len <= max_exp + 2
@@ -998,19 +996,19 @@ inline char* format_buffer(char* buf, int len, int decimal_exponent,
return buf + (static_cast<size_t>(n) + 2); return buf + (static_cast<size_t>(n) + 2);
} }
if (0 < n and n <= max_exp) if (0 < n && n <= max_exp)
{ {
// dig.its // dig.its
// len <= max_digits10 + 1 // len <= max_digits10 + 1
assert(k > n); JSON_ASSERT(k > n);
std::memmove(buf + (static_cast<size_t>(n) + 1), buf + n, static_cast<size_t>(k) - static_cast<size_t>(n)); std::memmove(buf + (static_cast<size_t>(n) + 1), buf + n, static_cast<size_t>(k) - static_cast<size_t>(n));
buf[n] = '.'; buf[n] = '.';
return buf + (static_cast<size_t>(k) + 1U); return buf + (static_cast<size_t>(k) + 1U);
} }
if (min_exp < n and n <= 0) if (min_exp < n && n <= 0)
{ {
// 0.[000]digits // 0.[000]digits
// len <= 2 + (-min_exp - 1) + max_digits10 // len <= 2 + (-min_exp - 1) + max_digits10
@@ -1061,7 +1059,7 @@ JSON_HEDLEY_RETURNS_NON_NULL
char* to_chars(char* first, const char* last, FloatType value) char* to_chars(char* first, const char* last, FloatType value)
{ {
static_cast<void>(last); // maybe unused - fix warning static_cast<void>(last); // maybe unused - fix warning
assert(std::isfinite(value)); JSON_ASSERT(std::isfinite(value));
// Use signbit(value) instead of (value < 0) since signbit works for -0. // Use signbit(value) instead of (value < 0) since signbit works for -0.
if (std::signbit(value)) if (std::signbit(value))
@@ -1079,7 +1077,7 @@ char* to_chars(char* first, const char* last, FloatType value)
return first; return first;
} }
assert(last - first >= std::numeric_limits<FloatType>::max_digits10); JSON_ASSERT(last - first >= std::numeric_limits<FloatType>::max_digits10);
// Compute v = buffer * 10^decimal_exponent. // Compute v = buffer * 10^decimal_exponent.
// The decimal digits are stored in the buffer, which needs to be interpreted // The decimal digits are stored in the buffer, which needs to be interpreted
@@ -1089,16 +1087,16 @@ char* to_chars(char* first, const char* last, FloatType value)
int decimal_exponent = 0; int decimal_exponent = 0;
dtoa_impl::grisu2(first, len, decimal_exponent, value); dtoa_impl::grisu2(first, len, decimal_exponent, value);
assert(len <= std::numeric_limits<FloatType>::max_digits10); JSON_ASSERT(len <= std::numeric_limits<FloatType>::max_digits10);
// Format the buffer like printf("%.*g", prec, value) // Format the buffer like printf("%.*g", prec, value)
constexpr int kMinExp = -4; constexpr int kMinExp = -4;
// Use digits10 here to increase compatibility with version 2. // Use digits10 here to increase compatibility with version 2.
constexpr int kMaxExp = std::numeric_limits<FloatType>::digits10; constexpr int kMaxExp = std::numeric_limits<FloatType>::digits10;
assert(last - first >= kMaxExp + 2); JSON_ASSERT(last - first >= kMaxExp + 2);
assert(last - first >= 2 + (-kMinExp - 1) + std::numeric_limits<FloatType>::max_digits10); JSON_ASSERT(last - first >= 2 + (-kMinExp - 1) + std::numeric_limits<FloatType>::max_digits10);
assert(last - first >= std::numeric_limits<FloatType>::max_digits10 + 6); JSON_ASSERT(last - first >= std::numeric_limits<FloatType>::max_digits10 + 6);
return dtoa_impl::format_buffer(first, len, decimal_exponent, kMinExp, kMaxExp); return dtoa_impl::format_buffer(first, len, decimal_exponent, kMinExp, kMaxExp);
} }
+10 -11
View File
@@ -9,7 +9,6 @@
#include <valarray> // valarray #include <valarray> // valarray
#include <vector> // vector #include <vector> // vector
#include <nlohmann/detail/boolean_operators.hpp>
#include <nlohmann/detail/iterators/iteration_proxy.hpp> #include <nlohmann/detail/iterators/iteration_proxy.hpp>
#include <nlohmann/detail/meta/cpp_future.hpp> #include <nlohmann/detail/meta/cpp_future.hpp>
#include <nlohmann/detail/meta/type_traits.hpp> #include <nlohmann/detail/meta/type_traits.hpp>
@@ -57,7 +56,7 @@ struct external_constructor<value_t::string>
} }
template < typename BasicJsonType, typename CompatibleStringType, template < typename BasicJsonType, typename CompatibleStringType,
enable_if_t<not std::is_same<CompatibleStringType, typename BasicJsonType::string_t>::value, enable_if_t < !std::is_same<CompatibleStringType, typename BasicJsonType::string_t>::value,
int > = 0 > int > = 0 >
static void construct(BasicJsonType& j, const CompatibleStringType& str) static void construct(BasicJsonType& j, const CompatibleStringType& str)
{ {
@@ -145,7 +144,7 @@ struct external_constructor<value_t::array>
} }
template < typename BasicJsonType, typename CompatibleArrayType, template < typename BasicJsonType, typename CompatibleArrayType,
enable_if_t<not std::is_same<CompatibleArrayType, typename BasicJsonType::array_t>::value, enable_if_t < !std::is_same<CompatibleArrayType, typename BasicJsonType::array_t>::value,
int > = 0 > int > = 0 >
static void construct(BasicJsonType& j, const CompatibleArrayType& arr) static void construct(BasicJsonType& j, const CompatibleArrayType& arr)
{ {
@@ -204,7 +203,7 @@ struct external_constructor<value_t::object>
} }
template < typename BasicJsonType, typename CompatibleObjectType, template < typename BasicJsonType, typename CompatibleObjectType,
enable_if_t<not std::is_same<CompatibleObjectType, typename BasicJsonType::object_t>::value, int> = 0> enable_if_t < !std::is_same<CompatibleObjectType, typename BasicJsonType::object_t>::value, int > = 0 >
static void construct(BasicJsonType& j, const CompatibleObjectType& obj) static void construct(BasicJsonType& j, const CompatibleObjectType& obj)
{ {
using std::begin; using std::begin;
@@ -277,11 +276,11 @@ void to_json(BasicJsonType& j, const std::vector<bool>& e)
template < typename BasicJsonType, typename CompatibleArrayType, template < typename BasicJsonType, typename CompatibleArrayType,
enable_if_t < is_compatible_array_type<BasicJsonType, enable_if_t < is_compatible_array_type<BasicJsonType,
CompatibleArrayType>::value and CompatibleArrayType>::value&&
not is_compatible_object_type<BasicJsonType, CompatibleArrayType>::value and !is_compatible_object_type<BasicJsonType, CompatibleArrayType>::value&&
not is_compatible_string_type<BasicJsonType, CompatibleArrayType>::value and !is_compatible_string_type<BasicJsonType, CompatibleArrayType>::value&&
not std::is_same<typename BasicJsonType::binary_t, CompatibleArrayType>::value and !std::is_same<typename BasicJsonType::binary_t, CompatibleArrayType>::value&&
not is_basic_json<CompatibleArrayType>::value, !is_basic_json<CompatibleArrayType>::value,
int > = 0 > int > = 0 >
void to_json(BasicJsonType& j, const CompatibleArrayType& arr) void to_json(BasicJsonType& j, const CompatibleArrayType& arr)
{ {
@@ -308,7 +307,7 @@ void to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr)
} }
template < typename BasicJsonType, typename CompatibleObjectType, template < typename BasicJsonType, typename CompatibleObjectType,
enable_if_t<is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value and not is_basic_json<CompatibleObjectType>::value, int> = 0> enable_if_t < is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value&& !is_basic_json<CompatibleObjectType>::value, int > = 0 >
void to_json(BasicJsonType& j, const CompatibleObjectType& obj) void to_json(BasicJsonType& j, const CompatibleObjectType& obj)
{ {
external_constructor<value_t::object>::construct(j, obj); external_constructor<value_t::object>::construct(j, obj);
@@ -322,7 +321,7 @@ void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj)
template < template <
typename BasicJsonType, typename T, std::size_t N, typename BasicJsonType, typename T, std::size_t N,
enable_if_t<not std::is_constructible<typename BasicJsonType::string_t, enable_if_t < !std::is_constructible<typename BasicJsonType::string_t,
const T(&)[N]>::value, const T(&)[N]>::value,
int > = 0 > int > = 0 >
void to_json(BasicJsonType& j, const T(&arr)[N]) void to_json(BasicJsonType& j, const T(&arr)[N])
File diff suppressed because it is too large Load Diff
@@ -1,7 +1,6 @@
#pragma once #pragma once
#include <array> // array #include <array> // array
#include <cassert> // assert
#include <cstddef> // size_t #include <cstddef> // size_t
#include <cstdio> //FILE * #include <cstdio> //FILE *
#include <cstring> // strlen #include <cstring> // strlen
@@ -76,7 +75,7 @@ class input_stream_adapter
{ {
// clear stream flags; we use underlying streambuf I/O, do not // clear stream flags; we use underlying streambuf I/O, do not
// maintain ifstream flags, except eof // maintain ifstream flags, except eof
if (is) if (is != nullptr)
{ {
is->clear(is->rdstate() & std::ios::eofbit); is->clear(is->rdstate() & std::ios::eofbit);
} }
@@ -251,7 +250,7 @@ struct wide_string_input_helper<BaseInputAdapter, 2>
utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu)); utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu));
utf8_bytes_filled = 2; utf8_bytes_filled = 2;
} }
else if (0xD800 > wc or wc >= 0xE000) else if (0xD800 > wc || wc >= 0xE000)
{ {
utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xE0u | ((static_cast<unsigned int>(wc) >> 12u))); utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xE0u | ((static_cast<unsigned int>(wc) >> 12u)));
utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 6u) & 0x3Fu)); utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 6u) & 0x3Fu));
@@ -260,7 +259,7 @@ struct wide_string_input_helper<BaseInputAdapter, 2>
} }
else else
{ {
if (JSON_HEDLEY_UNLIKELY(not input.empty())) if (JSON_HEDLEY_UNLIKELY(!input.empty()))
{ {
const auto wc2 = static_cast<unsigned int>(input.get_character()); const auto wc2 = static_cast<unsigned int>(input.get_character());
const auto charcode = 0x10000u + (((static_cast<unsigned int>(wc) & 0x3FFu) << 10u) | (wc2 & 0x3FFu)); const auto charcode = 0x10000u + (((static_cast<unsigned int>(wc) & 0x3FFu) << 10u) | (wc2 & 0x3FFu));
@@ -297,13 +296,13 @@ class wide_string_input_adapter
{ {
fill_buffer<sizeof(WideCharType)>(); fill_buffer<sizeof(WideCharType)>();
assert(utf8_bytes_filled > 0); JSON_ASSERT(utf8_bytes_filled > 0);
assert(utf8_bytes_index == 0); JSON_ASSERT(utf8_bytes_index == 0);
} }
// use buffer // use buffer
assert(utf8_bytes_filled > 0); JSON_ASSERT(utf8_bytes_filled > 0);
assert(utf8_bytes_index < utf8_bytes_filled); JSON_ASSERT(utf8_bytes_index < utf8_bytes_filled);
return utf8_bytes[utf8_bytes_index++]; return utf8_bytes[utf8_bytes_index++];
} }
@@ -403,15 +402,15 @@ using contiguous_bytes_input_adapter = decltype(input_adapter(std::declval<const
// Null-delimited strings, and the like. // Null-delimited strings, and the like.
template < typename CharT, template < typename CharT,
typename std::enable_if < typename std::enable_if <
std::is_pointer<CharT>::value and std::is_pointer<CharT>::value&&
not std::is_array<CharT>::value and !std::is_array<CharT>::value&&
std::is_integral<typename std::remove_pointer<CharT>::type>::value and std::is_integral<typename std::remove_pointer<CharT>::type>::value&&
sizeof(typename std::remove_pointer<CharT>::type) == 1, sizeof(typename std::remove_pointer<CharT>::type) == 1,
int >::type = 0 > int >::type = 0 >
contiguous_bytes_input_adapter input_adapter(CharT b) contiguous_bytes_input_adapter input_adapter(CharT b)
{ {
auto length = std::strlen(reinterpret_cast<const char*>(b)); auto length = std::strlen(reinterpret_cast<const char*>(b));
auto ptr = reinterpret_cast<const char*>(b); const auto* ptr = reinterpret_cast<const char*>(b);
return input_adapter(ptr, ptr + length); return input_adapter(ptr, ptr + length);
} }
@@ -429,8 +428,8 @@ class span_input_adapter
public: public:
template < typename CharT, template < typename CharT,
typename std::enable_if < typename std::enable_if <
std::is_pointer<CharT>::value and std::is_pointer<CharT>::value&&
std::is_integral<typename std::remove_pointer<CharT>::type>::value and std::is_integral<typename std::remove_pointer<CharT>::type>::value&&
sizeof(typename std::remove_pointer<CharT>::type) == 1, sizeof(typename std::remove_pointer<CharT>::type) == 1,
int >::type = 0 > int >::type = 0 >
span_input_adapter(CharT b, std::size_t l) span_input_adapter(CharT b, std::size_t l)
+38 -39
View File
@@ -1,6 +1,5 @@
#pragma once #pragma once
#include <cassert> // assert
#include <cstddef> #include <cstddef>
#include <string> // string #include <string> // string
#include <utility> // move #include <utility> // move
@@ -218,7 +217,7 @@ class json_sax_dom_parser
{ {
ref_stack.push_back(handle_value(BasicJsonType::value_t::object)); ref_stack.push_back(handle_value(BasicJsonType::value_t::object));
if (JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) and len > ref_stack.back()->max_size())) if (JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size()))
{ {
JSON_THROW(out_of_range::create(408, JSON_THROW(out_of_range::create(408,
"excessive object size: " + std::to_string(len))); "excessive object size: " + std::to_string(len)));
@@ -244,7 +243,7 @@ class json_sax_dom_parser
{ {
ref_stack.push_back(handle_value(BasicJsonType::value_t::array)); ref_stack.push_back(handle_value(BasicJsonType::value_t::array));
if (JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) and len > ref_stack.back()->max_size())) if (JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size()))
{ {
JSON_THROW(out_of_range::create(408, JSON_THROW(out_of_range::create(408,
"excessive array size: " + std::to_string(len))); "excessive array size: " + std::to_string(len)));
@@ -269,18 +268,18 @@ class json_sax_dom_parser
switch ((ex.id / 100) % 100) switch ((ex.id / 100) % 100)
{ {
case 1: case 1:
JSON_THROW(*static_cast<const detail::parse_error*>(&ex)); JSON_THROW(*dynamic_cast<const detail::parse_error*>(&ex));
case 4: case 4:
JSON_THROW(*static_cast<const detail::out_of_range*>(&ex)); JSON_THROW(*dynamic_cast<const detail::out_of_range*>(&ex));
// LCOV_EXCL_START // LCOV_EXCL_START
case 2: case 2:
JSON_THROW(*static_cast<const detail::invalid_iterator*>(&ex)); JSON_THROW(*dynamic_cast<const detail::invalid_iterator*>(&ex));
case 3: case 3:
JSON_THROW(*static_cast<const detail::type_error*>(&ex)); JSON_THROW(*dynamic_cast<const detail::type_error*>(&ex));
case 5: case 5:
JSON_THROW(*static_cast<const detail::other_error*>(&ex)); JSON_THROW(*dynamic_cast<const detail::other_error*>(&ex));
default: default:
assert(false); JSON_ASSERT(false);
// LCOV_EXCL_STOP // LCOV_EXCL_STOP
} }
} }
@@ -309,7 +308,7 @@ class json_sax_dom_parser
return &root; return &root;
} }
assert(ref_stack.back()->is_array() or ref_stack.back()->is_object()); JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object());
if (ref_stack.back()->is_array()) if (ref_stack.back()->is_array())
{ {
@@ -317,8 +316,8 @@ class json_sax_dom_parser
return &(ref_stack.back()->m_value.array->back()); return &(ref_stack.back()->m_value.array->back());
} }
assert(ref_stack.back()->is_object()); JSON_ASSERT(ref_stack.back()->is_object());
assert(object_element); JSON_ASSERT(object_element);
*object_element = BasicJsonType(std::forward<Value>(v)); *object_element = BasicJsonType(std::forward<Value>(v));
return object_element; return object_element;
} }
@@ -414,7 +413,7 @@ class json_sax_dom_callback_parser
ref_stack.push_back(val.second); ref_stack.push_back(val.second);
// check object limit // check object limit
if (ref_stack.back() and JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) and len > ref_stack.back()->max_size())) if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size()))
{ {
JSON_THROW(out_of_range::create(408, "excessive object size: " + std::to_string(len))); JSON_THROW(out_of_range::create(408, "excessive object size: " + std::to_string(len)));
} }
@@ -431,7 +430,7 @@ class json_sax_dom_callback_parser
key_keep_stack.push_back(keep); key_keep_stack.push_back(keep);
// add discarded value at given key and store the reference for later // add discarded value at given key and store the reference for later
if (keep and ref_stack.back()) if (keep && ref_stack.back())
{ {
object_element = &(ref_stack.back()->m_value.object->operator[](val) = discarded); object_element = &(ref_stack.back()->m_value.object->operator[](val) = discarded);
} }
@@ -441,18 +440,18 @@ class json_sax_dom_callback_parser
bool end_object() bool end_object()
{ {
if (ref_stack.back() and not callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back())) if (ref_stack.back() && !callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back()))
{ {
// discard object // discard object
*ref_stack.back() = discarded; *ref_stack.back() = discarded;
} }
assert(not ref_stack.empty()); JSON_ASSERT(!ref_stack.empty());
assert(not keep_stack.empty()); JSON_ASSERT(!keep_stack.empty());
ref_stack.pop_back(); ref_stack.pop_back();
keep_stack.pop_back(); keep_stack.pop_back();
if (not ref_stack.empty() and ref_stack.back() and ref_stack.back()->is_structured()) if (!ref_stack.empty() && ref_stack.back() && ref_stack.back()->is_structured())
{ {
// remove discarded value // remove discarded value
for (auto it = ref_stack.back()->begin(); it != ref_stack.back()->end(); ++it) for (auto it = ref_stack.back()->begin(); it != ref_stack.back()->end(); ++it)
@@ -477,7 +476,7 @@ class json_sax_dom_callback_parser
ref_stack.push_back(val.second); ref_stack.push_back(val.second);
// check array limit // check array limit
if (ref_stack.back() and JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) and len > ref_stack.back()->max_size())) if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size()))
{ {
JSON_THROW(out_of_range::create(408, "excessive array size: " + std::to_string(len))); JSON_THROW(out_of_range::create(408, "excessive array size: " + std::to_string(len)));
} }
@@ -492,20 +491,20 @@ class json_sax_dom_callback_parser
if (ref_stack.back()) if (ref_stack.back())
{ {
keep = callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::array_end, *ref_stack.back()); keep = callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::array_end, *ref_stack.back());
if (not keep) if (!keep)
{ {
// discard array // discard array
*ref_stack.back() = discarded; *ref_stack.back() = discarded;
} }
} }
assert(not ref_stack.empty()); JSON_ASSERT(!ref_stack.empty());
assert(not keep_stack.empty()); JSON_ASSERT(!keep_stack.empty());
ref_stack.pop_back(); ref_stack.pop_back();
keep_stack.pop_back(); keep_stack.pop_back();
// remove discarded value // remove discarded value
if (not keep and not ref_stack.empty() and ref_stack.back()->is_array()) if (!keep && !ref_stack.empty() && ref_stack.back()->is_array())
{ {
ref_stack.back()->m_value.array->pop_back(); ref_stack.back()->m_value.array->pop_back();
} }
@@ -523,18 +522,18 @@ class json_sax_dom_callback_parser
switch ((ex.id / 100) % 100) switch ((ex.id / 100) % 100)
{ {
case 1: case 1:
JSON_THROW(*static_cast<const detail::parse_error*>(&ex)); JSON_THROW(*dynamic_cast<const detail::parse_error*>(&ex));
case 4: case 4:
JSON_THROW(*static_cast<const detail::out_of_range*>(&ex)); JSON_THROW(*dynamic_cast<const detail::out_of_range*>(&ex));
// LCOV_EXCL_START // LCOV_EXCL_START
case 2: case 2:
JSON_THROW(*static_cast<const detail::invalid_iterator*>(&ex)); JSON_THROW(*dynamic_cast<const detail::invalid_iterator*>(&ex));
case 3: case 3:
JSON_THROW(*static_cast<const detail::type_error*>(&ex)); JSON_THROW(*dynamic_cast<const detail::type_error*>(&ex));
case 5: case 5:
JSON_THROW(*static_cast<const detail::other_error*>(&ex)); JSON_THROW(*dynamic_cast<const detail::other_error*>(&ex));
default: default:
assert(false); JSON_ASSERT(false);
// LCOV_EXCL_STOP // LCOV_EXCL_STOP
} }
} }
@@ -565,11 +564,11 @@ class json_sax_dom_callback_parser
template<typename Value> template<typename Value>
std::pair<bool, BasicJsonType*> handle_value(Value&& v, const bool skip_callback = false) std::pair<bool, BasicJsonType*> handle_value(Value&& v, const bool skip_callback = false)
{ {
assert(not keep_stack.empty()); JSON_ASSERT(!keep_stack.empty());
// do not handle this value if we know it would be added to a discarded // do not handle this value if we know it would be added to a discarded
// container // container
if (not keep_stack.back()) if (!keep_stack.back())
{ {
return {false, nullptr}; return {false, nullptr};
} }
@@ -578,10 +577,10 @@ class json_sax_dom_callback_parser
auto value = BasicJsonType(std::forward<Value>(v)); auto value = BasicJsonType(std::forward<Value>(v));
// check callback // check callback
const bool keep = skip_callback or callback(static_cast<int>(ref_stack.size()), parse_event_t::value, value); const bool keep = skip_callback || callback(static_cast<int>(ref_stack.size()), parse_event_t::value, value);
// do not handle this value if we just learnt it shall be discarded // do not handle this value if we just learnt it shall be discarded
if (not keep) if (!keep)
{ {
return {false, nullptr}; return {false, nullptr};
} }
@@ -594,13 +593,13 @@ class json_sax_dom_callback_parser
// skip this value if we already decided to skip the parent // skip this value if we already decided to skip the parent
// (https://github.com/nlohmann/json/issues/971#issuecomment-413678360) // (https://github.com/nlohmann/json/issues/971#issuecomment-413678360)
if (not ref_stack.back()) if (!ref_stack.back())
{ {
return {false, nullptr}; return {false, nullptr};
} }
// we now only expect arrays and objects // we now only expect arrays and objects
assert(ref_stack.back()->is_array() or ref_stack.back()->is_object()); JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object());
// array // array
if (ref_stack.back()->is_array()) if (ref_stack.back()->is_array())
@@ -610,18 +609,18 @@ class json_sax_dom_callback_parser
} }
// object // object
assert(ref_stack.back()->is_object()); JSON_ASSERT(ref_stack.back()->is_object());
// check if we should store an element for the current key // check if we should store an element for the current key
assert(not key_keep_stack.empty()); JSON_ASSERT(!key_keep_stack.empty());
const bool store_element = key_keep_stack.back(); const bool store_element = key_keep_stack.back();
key_keep_stack.pop_back(); key_keep_stack.pop_back();
if (not store_element) if (!store_element)
{ {
return {false, nullptr}; return {false, nullptr};
} }
assert(object_element); JSON_ASSERT(object_element);
*object_element = std::move(value); *object_element = std::move(value);
return {true, object_element}; return {true, object_element};
} }
+195 -37
View File
@@ -13,6 +13,7 @@
#include <nlohmann/detail/input/input_adapters.hpp> #include <nlohmann/detail/input/input_adapters.hpp>
#include <nlohmann/detail/input/position_t.hpp> #include <nlohmann/detail/input/position_t.hpp>
#include <nlohmann/detail/macro_scope.hpp> #include <nlohmann/detail/macro_scope.hpp>
#include <nlohmann/detail/meta/type_traits.hpp>
namespace nlohmann namespace nlohmann
{ {
@@ -112,8 +113,11 @@ class lexer : public lexer_base<BasicJsonType>
public: public:
using token_type = typename lexer_base<BasicJsonType>::token_type; using token_type = typename lexer_base<BasicJsonType>::token_type;
explicit lexer(InputAdapterType&& adapter) explicit lexer(InputAdapterType&& adapter, bool ignore_comments_ = false)
: ia(std::move(adapter)), decimal_point_char(static_cast<char_int_type>(get_decimal_point())) {} : ia(std::move(adapter))
, ignore_comments(ignore_comments_)
, decimal_point_char(static_cast<char_int_type>(get_decimal_point()))
{}
// delete because of pointer members // delete because of pointer members
lexer(const lexer&) = delete; lexer(const lexer&) = delete;
@@ -131,8 +135,8 @@ class lexer : public lexer_base<BasicJsonType>
JSON_HEDLEY_PURE JSON_HEDLEY_PURE
static char get_decimal_point() noexcept static char get_decimal_point() noexcept
{ {
const auto loc = localeconv(); const auto* loc = localeconv();
assert(loc != nullptr); JSON_ASSERT(loc != nullptr);
return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point); return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point);
} }
@@ -158,7 +162,7 @@ class lexer : public lexer_base<BasicJsonType>
int get_codepoint() int get_codepoint()
{ {
// this function only makes sense after reading `\u` // this function only makes sense after reading `\u`
assert(current == 'u'); JSON_ASSERT(current == 'u');
int codepoint = 0; int codepoint = 0;
const auto factors = { 12u, 8u, 4u, 0u }; const auto factors = { 12u, 8u, 4u, 0u };
@@ -166,15 +170,15 @@ class lexer : public lexer_base<BasicJsonType>
{ {
get(); get();
if (current >= '0' and current <= '9') if (current >= '0' && current <= '9')
{ {
codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x30u) << factor); codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x30u) << factor);
} }
else if (current >= 'A' and current <= 'F') else if (current >= 'A' && current <= 'F')
{ {
codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x37u) << factor); codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x37u) << factor);
} }
else if (current >= 'a' and current <= 'f') else if (current >= 'a' && current <= 'f')
{ {
codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x57u) << factor); codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x57u) << factor);
} }
@@ -184,7 +188,7 @@ class lexer : public lexer_base<BasicJsonType>
} }
} }
assert(0x0000 <= codepoint and codepoint <= 0xFFFF); JSON_ASSERT(0x0000 <= codepoint && codepoint <= 0xFFFF);
return codepoint; return codepoint;
} }
@@ -205,13 +209,13 @@ class lexer : public lexer_base<BasicJsonType>
*/ */
bool next_byte_in_range(std::initializer_list<char_int_type> ranges) bool next_byte_in_range(std::initializer_list<char_int_type> ranges)
{ {
assert(ranges.size() == 2 or ranges.size() == 4 or ranges.size() == 6); JSON_ASSERT(ranges.size() == 2 || ranges.size() == 4 || ranges.size() == 6);
add(current); add(current);
for (auto range = ranges.begin(); range != ranges.end(); ++range) for (auto range = ranges.begin(); range != ranges.end(); ++range)
{ {
get(); get();
if (JSON_HEDLEY_LIKELY(*range <= current and current <= *(++range))) if (JSON_HEDLEY_LIKELY(*range <= current && current <= *(++range)))
{ {
add(current); add(current);
} }
@@ -246,7 +250,7 @@ class lexer : public lexer_base<BasicJsonType>
reset(); reset();
// we entered the function by reading an open quote // we entered the function by reading an open quote
assert(current == '\"'); JSON_ASSERT(current == '\"');
while (true) while (true)
{ {
@@ -317,10 +321,10 @@ class lexer : public lexer_base<BasicJsonType>
} }
// check if code point is a high surrogate // check if code point is a high surrogate
if (0xD800 <= codepoint1 and codepoint1 <= 0xDBFF) if (0xD800 <= codepoint1 && codepoint1 <= 0xDBFF)
{ {
// expect next \uxxxx entry // expect next \uxxxx entry
if (JSON_HEDLEY_LIKELY(get() == '\\' and get() == 'u')) if (JSON_HEDLEY_LIKELY(get() == '\\' && get() == 'u'))
{ {
const int codepoint2 = get_codepoint(); const int codepoint2 = get_codepoint();
@@ -331,7 +335,7 @@ class lexer : public lexer_base<BasicJsonType>
} }
// check if codepoint2 is a low surrogate // check if codepoint2 is a low surrogate
if (JSON_HEDLEY_LIKELY(0xDC00 <= codepoint2 and codepoint2 <= 0xDFFF)) if (JSON_HEDLEY_LIKELY(0xDC00 <= codepoint2 && codepoint2 <= 0xDFFF))
{ {
// overwrite codepoint // overwrite codepoint
codepoint = static_cast<int>( codepoint = static_cast<int>(
@@ -358,7 +362,7 @@ class lexer : public lexer_base<BasicJsonType>
} }
else else
{ {
if (JSON_HEDLEY_UNLIKELY(0xDC00 <= codepoint1 and codepoint1 <= 0xDFFF)) if (JSON_HEDLEY_UNLIKELY(0xDC00 <= codepoint1 && codepoint1 <= 0xDFFF))
{ {
error_message = "invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF"; error_message = "invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF";
return token_type::parse_error; return token_type::parse_error;
@@ -366,7 +370,7 @@ class lexer : public lexer_base<BasicJsonType>
} }
// result of the above calculation yields a proper codepoint // result of the above calculation yields a proper codepoint
assert(0x00 <= codepoint and codepoint <= 0x10FFFF); JSON_ASSERT(0x00 <= codepoint && codepoint <= 0x10FFFF);
// translate codepoint into bytes // translate codepoint into bytes
if (codepoint < 0x80) if (codepoint < 0x80)
@@ -733,7 +737,7 @@ class lexer : public lexer_base<BasicJsonType>
case 0xDE: case 0xDE:
case 0xDF: case 0xDF:
{ {
if (JSON_HEDLEY_UNLIKELY(not next_byte_in_range({0x80, 0xBF}))) if (JSON_HEDLEY_UNLIKELY(!next_byte_in_range({0x80, 0xBF})))
{ {
return token_type::parse_error; return token_type::parse_error;
} }
@@ -743,7 +747,7 @@ class lexer : public lexer_base<BasicJsonType>
// U+0800..U+0FFF: bytes E0 A0..BF 80..BF // U+0800..U+0FFF: bytes E0 A0..BF 80..BF
case 0xE0: case 0xE0:
{ {
if (JSON_HEDLEY_UNLIKELY(not (next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF})))) if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF}))))
{ {
return token_type::parse_error; return token_type::parse_error;
} }
@@ -767,7 +771,7 @@ class lexer : public lexer_base<BasicJsonType>
case 0xEE: case 0xEE:
case 0xEF: case 0xEF:
{ {
if (JSON_HEDLEY_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF})))) if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0xBF, 0x80, 0xBF}))))
{ {
return token_type::parse_error; return token_type::parse_error;
} }
@@ -777,7 +781,7 @@ class lexer : public lexer_base<BasicJsonType>
// U+D000..U+D7FF: bytes ED 80..9F 80..BF // U+D000..U+D7FF: bytes ED 80..9F 80..BF
case 0xED: case 0xED:
{ {
if (JSON_HEDLEY_UNLIKELY(not (next_byte_in_range({0x80, 0x9F, 0x80, 0xBF})))) if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0x9F, 0x80, 0xBF}))))
{ {
return token_type::parse_error; return token_type::parse_error;
} }
@@ -787,7 +791,7 @@ class lexer : public lexer_base<BasicJsonType>
// U+10000..U+3FFFF F0 90..BF 80..BF 80..BF // U+10000..U+3FFFF F0 90..BF 80..BF 80..BF
case 0xF0: case 0xF0:
{ {
if (JSON_HEDLEY_UNLIKELY(not (next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF}))))
{ {
return token_type::parse_error; return token_type::parse_error;
} }
@@ -799,7 +803,7 @@ class lexer : public lexer_base<BasicJsonType>
case 0xF2: case 0xF2:
case 0xF3: case 0xF3:
{ {
if (JSON_HEDLEY_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF}))))
{ {
return token_type::parse_error; return token_type::parse_error;
} }
@@ -809,7 +813,7 @@ class lexer : public lexer_base<BasicJsonType>
// U+100000..U+10FFFF F4 80..8F 80..BF 80..BF // U+100000..U+10FFFF F4 80..8F 80..BF 80..BF
case 0xF4: case 0xF4:
{ {
if (JSON_HEDLEY_UNLIKELY(not (next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF})))) if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF}))))
{ {
return token_type::parse_error; return token_type::parse_error;
} }
@@ -826,6 +830,77 @@ class lexer : public lexer_base<BasicJsonType>
} }
} }
/*!
* @brief scan a comment
* @return whether comment could be scanned successfully
*/
bool scan_comment()
{
switch (get())
{
// single-line comments skip input until a newline or EOF is read
case '/':
{
while (true)
{
switch (get())
{
case '\n':
case '\r':
case std::char_traits<char_type>::eof():
case '\0':
return true;
default:
break;
}
}
}
// multi-line comments skip input until */ is read
case '*':
{
while (true)
{
switch (get())
{
case std::char_traits<char_type>::eof():
case '\0':
{
error_message = "invalid comment; missing closing '*/'";
return false;
}
case '*':
{
switch (get())
{
case '/':
return true;
default:
{
unget();
break;
}
}
}
default:
break;
}
}
}
// unexpected character after reading '/'
default:
{
error_message = "invalid comment; expecting '/' or '*' after '/'";
return false;
}
}
}
JSON_HEDLEY_NON_NULL(2) JSON_HEDLEY_NON_NULL(2)
static void strtof(float& f, const char* str, char** endptr) noexcept static void strtof(float& f, const char* str, char** endptr) noexcept
{ {
@@ -844,6 +919,68 @@ class lexer : public lexer_base<BasicJsonType>
f = std::strtold(str, endptr); f = std::strtold(str, endptr);
} }
JSON_HEDLEY_NON_NULL(2)
unsigned long long strtoull(const char* str, char** str_end, std::true_type)
{
return std::strtoull(str, str_end, 10);
}
JSON_HEDLEY_NON_NULL(2)
number_unsigned_t strtoull(const char* str, char** str_end, std::false_type)
{
number_unsigned_t val = 0;
const char* p = str;
while (*p >= '0' && * p <= '9')
{
val = (10U * val) + static_cast<number_unsigned_t>((*p - '0'));
p++;
}
if (str_end != nullptr)
{
*str_end = const_cast<char*>(p);
}
return val;
}
JSON_HEDLEY_NON_NULL(2)
long long strtoll(const char* str, char** str_end, std::true_type)
{
return std::strtoll(str, str_end, 10);
}
JSON_HEDLEY_NON_NULL(2)
number_integer_t strtoll(const char* str, char** str_end, std::false_type)
{
number_integer_t val = 0;
const char* p = str;
if (*p == '-')
{
p++;
}
while (*p >= '0' and * p <= '9')
{
val = (10 * val) + (*p - '0');
p++;
}
if (*str == '-')
{
val = val * -1;
}
if (str_end != nullptr)
{
*str_end = const_cast<char*>(p);
}
return val;
}
/*! /*!
@brief scan a number literal @brief scan a number literal
@@ -924,7 +1061,7 @@ class lexer : public lexer_base<BasicJsonType>
// all other characters are rejected outside scan_number() // all other characters are rejected outside scan_number()
default: // LCOV_EXCL_LINE default: // LCOV_EXCL_LINE
assert(false); // LCOV_EXCL_LINE JSON_ASSERT(false); // LCOV_EXCL_LINE
} }
scan_number_minus: scan_number_minus:
@@ -1168,10 +1305,10 @@ scan_number_done:
// try to parse integers first and fall back to floats // try to parse integers first and fall back to floats
if (number_type == token_type::value_unsigned) if (number_type == token_type::value_unsigned)
{ {
const auto x = std::strtoull(token_buffer.data(), &endptr, 10); const auto x = strtoull(token_buffer.data(), &endptr, is_64_bit<number_unsigned_t>());
// we checked the number format before // we checked the number format before
assert(endptr == token_buffer.data() + token_buffer.size()); JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size());
if (errno == 0) if (errno == 0)
{ {
@@ -1184,10 +1321,10 @@ scan_number_done:
} }
else if (number_type == token_type::value_integer) else if (number_type == token_type::value_integer)
{ {
const auto x = std::strtoll(token_buffer.data(), &endptr, 10); const auto x = strtoll(token_buffer.data(), &endptr, is_64_bit<number_integer_t>());
// we checked the number format before // we checked the number format before
assert(endptr == token_buffer.data() + token_buffer.size()); JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size());
if (errno == 0) if (errno == 0)
{ {
@@ -1204,7 +1341,7 @@ scan_number_done:
strtof(value_float, token_buffer.data(), &endptr); strtof(value_float, token_buffer.data(), &endptr);
// we checked the number format before // we checked the number format before
assert(endptr == token_buffer.data() + token_buffer.size()); JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size());
return token_type::value_float; return token_type::value_float;
} }
@@ -1218,7 +1355,7 @@ scan_number_done:
token_type scan_literal(const char_type* literal_text, const std::size_t length, token_type scan_literal(const char_type* literal_text, const std::size_t length,
token_type return_type) token_type return_type)
{ {
assert(std::char_traits<char_type>::to_char_type(current) == literal_text[0]); JSON_ASSERT(std::char_traits<char_type>::to_char_type(current) == literal_text[0]);
for (std::size_t i = 1; i < length; ++i) for (std::size_t i = 1; i < length; ++i)
{ {
if (JSON_HEDLEY_UNLIKELY(std::char_traits<char_type>::to_char_type(get()) != literal_text[i])) if (JSON_HEDLEY_UNLIKELY(std::char_traits<char_type>::to_char_type(get()) != literal_text[i]))
@@ -1310,7 +1447,7 @@ scan_number_done:
if (JSON_HEDLEY_LIKELY(current != std::char_traits<char_type>::eof())) if (JSON_HEDLEY_LIKELY(current != std::char_traits<char_type>::eof()))
{ {
assert(not token_string.empty()); JSON_ASSERT(!token_string.empty());
token_string.pop_back(); token_string.pop_back();
} }
} }
@@ -1406,7 +1543,7 @@ scan_number_done:
if (get() == 0xEF) if (get() == 0xEF)
{ {
// check if we completely parse the BOM // check if we completely parse the BOM
return get() == 0xBB and get() == 0xBF; return get() == 0xBB && get() == 0xBF;
} }
// the first character is not the beginning of the BOM; unget it to // the first character is not the beginning of the BOM; unget it to
@@ -1415,21 +1552,39 @@ scan_number_done:
return true; return true;
} }
void skip_whitespace()
{
do
{
get();
}
while (current == ' ' || current == '\t' || current == '\n' || current == '\r');
}
token_type scan() token_type scan()
{ {
// initially, skip the BOM // initially, skip the BOM
if (position.chars_read_total == 0 and not skip_bom()) if (position.chars_read_total == 0 && !skip_bom())
{ {
error_message = "invalid BOM; must be 0xEF 0xBB 0xBF if given"; error_message = "invalid BOM; must be 0xEF 0xBB 0xBF if given";
return token_type::parse_error; return token_type::parse_error;
} }
// read next character and ignore whitespace // read next character and ignore whitespace
do skip_whitespace();
// ignore comments
if (ignore_comments && current == '/')
{ {
get(); if (!scan_comment())
{
return token_type::parse_error;
} }
while (current == ' ' or current == '\t' or current == '\n' or current == '\r');
// skip following whitespace
skip_whitespace();
}
while (current == ' ' || current == '\t' || current == '\n' || current == '\r');
switch (current) switch (current)
{ {
@@ -1499,6 +1654,9 @@ scan_number_done:
/// input adapter /// input adapter
InputAdapterType ia; InputAdapterType ia;
/// whether comments should be ignored (true) or signaled as errors (false)
const bool ignore_comments = false;
/// the current character /// the current character
char_int_type current = std::char_traits<char_type>::eof(); char_int_type current = std::char_traits<char_type>::eof();
+28 -26
View File
@@ -1,6 +1,5 @@
#pragma once #pragma once
#include <cassert> // assert
#include <cmath> // isfinite #include <cmath> // isfinite
#include <cstdint> // uint8_t #include <cstdint> // uint8_t
#include <functional> // function #include <functional> // function
@@ -63,8 +62,11 @@ class parser
/// a parser reading from an input adapter /// a parser reading from an input adapter
explicit parser(InputAdapterType&& adapter, explicit parser(InputAdapterType&& adapter,
const parser_callback_t<BasicJsonType> cb = nullptr, const parser_callback_t<BasicJsonType> cb = nullptr,
const bool allow_exceptions_ = true) const bool allow_exceptions_ = true,
: callback(cb), m_lexer(std::move(adapter)), allow_exceptions(allow_exceptions_) const bool skip_comments = false)
: callback(cb)
, m_lexer(std::move(adapter), skip_comments)
, allow_exceptions(allow_exceptions_)
{ {
// read first token // read first token
get_token(); get_token();
@@ -89,7 +91,7 @@ class parser
result.assert_invariant(); result.assert_invariant();
// in strict mode, input must be completely read // in strict mode, input must be completely read
if (strict and (get_token() != token_type::end_of_input)) if (strict && (get_token() != token_type::end_of_input))
{ {
sdp.parse_error(m_lexer.get_position(), sdp.parse_error(m_lexer.get_position(),
m_lexer.get_token_string(), m_lexer.get_token_string(),
@@ -118,7 +120,7 @@ class parser
result.assert_invariant(); result.assert_invariant();
// in strict mode, input must be completely read // in strict mode, input must be completely read
if (strict and (get_token() != token_type::end_of_input)) if (strict && (get_token() != token_type::end_of_input))
{ {
sdp.parse_error(m_lexer.get_position(), sdp.parse_error(m_lexer.get_position(),
m_lexer.get_token_string(), m_lexer.get_token_string(),
@@ -155,7 +157,7 @@ class parser
const bool result = sax_parse_internal(sax); const bool result = sax_parse_internal(sax);
// strict mode: next byte must be EOF // strict mode: next byte must be EOF
if (result and strict and (get_token() != token_type::end_of_input)) if (result && strict && (get_token() != token_type::end_of_input))
{ {
return sax->parse_error(m_lexer.get_position(), return sax->parse_error(m_lexer.get_position(),
m_lexer.get_token_string(), m_lexer.get_token_string(),
@@ -179,14 +181,14 @@ class parser
while (true) while (true)
{ {
if (not skip_to_state_evaluation) if (!skip_to_state_evaluation)
{ {
// invariant: get_token() was called before each iteration // invariant: get_token() was called before each iteration
switch (last_token) switch (last_token)
{ {
case token_type::begin_object: case token_type::begin_object:
{ {
if (JSON_HEDLEY_UNLIKELY(not sax->start_object(std::size_t(-1)))) if (JSON_HEDLEY_UNLIKELY(!sax->start_object(std::size_t(-1))))
{ {
return false; return false;
} }
@@ -194,7 +196,7 @@ class parser
// closing } -> we are done // closing } -> we are done
if (get_token() == token_type::end_object) if (get_token() == token_type::end_object)
{ {
if (JSON_HEDLEY_UNLIKELY(not sax->end_object())) if (JSON_HEDLEY_UNLIKELY(!sax->end_object()))
{ {
return false; return false;
} }
@@ -209,7 +211,7 @@ class parser
parse_error::create(101, m_lexer.get_position(), parse_error::create(101, m_lexer.get_position(),
exception_message(token_type::value_string, "object key"))); exception_message(token_type::value_string, "object key")));
} }
if (JSON_HEDLEY_UNLIKELY(not sax->key(m_lexer.get_string()))) if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string())))
{ {
return false; return false;
} }
@@ -233,7 +235,7 @@ class parser
case token_type::begin_array: case token_type::begin_array:
{ {
if (JSON_HEDLEY_UNLIKELY(not sax->start_array(std::size_t(-1)))) if (JSON_HEDLEY_UNLIKELY(!sax->start_array(std::size_t(-1))))
{ {
return false; return false;
} }
@@ -241,7 +243,7 @@ class parser
// closing ] -> we are done // closing ] -> we are done
if (get_token() == token_type::end_array) if (get_token() == token_type::end_array)
{ {
if (JSON_HEDLEY_UNLIKELY(not sax->end_array())) if (JSON_HEDLEY_UNLIKELY(!sax->end_array()))
{ {
return false; return false;
} }
@@ -259,14 +261,14 @@ class parser
{ {
const auto res = m_lexer.get_number_float(); const auto res = m_lexer.get_number_float();
if (JSON_HEDLEY_UNLIKELY(not std::isfinite(res))) if (JSON_HEDLEY_UNLIKELY(!std::isfinite(res)))
{ {
return sax->parse_error(m_lexer.get_position(), return sax->parse_error(m_lexer.get_position(),
m_lexer.get_token_string(), m_lexer.get_token_string(),
out_of_range::create(406, "number overflow parsing '" + m_lexer.get_token_string() + "'")); out_of_range::create(406, "number overflow parsing '" + m_lexer.get_token_string() + "'"));
} }
if (JSON_HEDLEY_UNLIKELY(not sax->number_float(res, m_lexer.get_string()))) if (JSON_HEDLEY_UNLIKELY(!sax->number_float(res, m_lexer.get_string())))
{ {
return false; return false;
} }
@@ -276,7 +278,7 @@ class parser
case token_type::literal_false: case token_type::literal_false:
{ {
if (JSON_HEDLEY_UNLIKELY(not sax->boolean(false))) if (JSON_HEDLEY_UNLIKELY(!sax->boolean(false)))
{ {
return false; return false;
} }
@@ -285,7 +287,7 @@ class parser
case token_type::literal_null: case token_type::literal_null:
{ {
if (JSON_HEDLEY_UNLIKELY(not sax->null())) if (JSON_HEDLEY_UNLIKELY(!sax->null()))
{ {
return false; return false;
} }
@@ -294,7 +296,7 @@ class parser
case token_type::literal_true: case token_type::literal_true:
{ {
if (JSON_HEDLEY_UNLIKELY(not sax->boolean(true))) if (JSON_HEDLEY_UNLIKELY(!sax->boolean(true)))
{ {
return false; return false;
} }
@@ -303,7 +305,7 @@ class parser
case token_type::value_integer: case token_type::value_integer:
{ {
if (JSON_HEDLEY_UNLIKELY(not sax->number_integer(m_lexer.get_number_integer()))) if (JSON_HEDLEY_UNLIKELY(!sax->number_integer(m_lexer.get_number_integer())))
{ {
return false; return false;
} }
@@ -312,7 +314,7 @@ class parser
case token_type::value_string: case token_type::value_string:
{ {
if (JSON_HEDLEY_UNLIKELY(not sax->string(m_lexer.get_string()))) if (JSON_HEDLEY_UNLIKELY(!sax->string(m_lexer.get_string())))
{ {
return false; return false;
} }
@@ -321,7 +323,7 @@ class parser
case token_type::value_unsigned: case token_type::value_unsigned:
{ {
if (JSON_HEDLEY_UNLIKELY(not sax->number_unsigned(m_lexer.get_number_unsigned()))) if (JSON_HEDLEY_UNLIKELY(!sax->number_unsigned(m_lexer.get_number_unsigned())))
{ {
return false; return false;
} }
@@ -371,7 +373,7 @@ class parser
// closing ] // closing ]
if (JSON_HEDLEY_LIKELY(last_token == token_type::end_array)) if (JSON_HEDLEY_LIKELY(last_token == token_type::end_array))
{ {
if (JSON_HEDLEY_UNLIKELY(not sax->end_array())) if (JSON_HEDLEY_UNLIKELY(!sax->end_array()))
{ {
return false; return false;
} }
@@ -380,7 +382,7 @@ class parser
// new value, we need to evaluate the new state first. // new value, we need to evaluate the new state first.
// By setting skip_to_state_evaluation to false, we // By setting skip_to_state_evaluation to false, we
// are effectively jumping to the beginning of this if. // are effectively jumping to the beginning of this if.
assert(not states.empty()); JSON_ASSERT(!states.empty());
states.pop_back(); states.pop_back();
skip_to_state_evaluation = true; skip_to_state_evaluation = true;
continue; continue;
@@ -405,7 +407,7 @@ class parser
exception_message(token_type::value_string, "object key"))); exception_message(token_type::value_string, "object key")));
} }
if (JSON_HEDLEY_UNLIKELY(not sax->key(m_lexer.get_string()))) if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string())))
{ {
return false; return false;
} }
@@ -427,7 +429,7 @@ class parser
// closing } // closing }
if (JSON_HEDLEY_LIKELY(last_token == token_type::end_object)) if (JSON_HEDLEY_LIKELY(last_token == token_type::end_object))
{ {
if (JSON_HEDLEY_UNLIKELY(not sax->end_object())) if (JSON_HEDLEY_UNLIKELY(!sax->end_object()))
{ {
return false; return false;
} }
@@ -436,7 +438,7 @@ class parser
// new value, we need to evaluate the new state first. // new value, we need to evaluate the new state first.
// By setting skip_to_state_evaluation to false, we // By setting skip_to_state_evaluation to false, we
// are effectively jumping to the beginning of this if. // are effectively jumping to the beginning of this if.
assert(not states.empty()); JSON_ASSERT(!states.empty());
states.pop_back(); states.pop_back();
skip_to_state_evaluation = true; skip_to_state_evaluation = true;
continue; continue;
@@ -460,7 +462,7 @@ class parser
{ {
std::string error_msg = "syntax error "; std::string error_msg = "syntax error ";
if (not context.empty()) if (!context.empty())
{ {
error_msg += "while parsing " + context + " "; error_msg += "while parsing " + context + " ";
} }
@@ -18,8 +18,6 @@ template<typename BasicJsonType> struct internal_iterator
typename BasicJsonType::object_t::iterator object_iterator {}; typename BasicJsonType::object_t::iterator object_iterator {};
/// iterator for JSON arrays /// iterator for JSON arrays
typename BasicJsonType::array_t::iterator array_iterator {}; typename BasicJsonType::array_t::iterator array_iterator {};
/// iterator for JSON binary arrays
typename BasicJsonType::binary_t::container_type::iterator binary_iterator {};
/// generic iterator for all other types /// generic iterator for all other types
primitive_iterator_t primitive_iterator {}; primitive_iterator_t primitive_iterator {};
}; };
+21 -22
View File
@@ -3,7 +3,6 @@
#include <iterator> // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next #include <iterator> // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next
#include <type_traits> // conditional, is_const, remove_const #include <type_traits> // conditional, is_const, remove_const
#include <nlohmann/detail/boolean_operators.hpp>
#include <nlohmann/detail/exceptions.hpp> #include <nlohmann/detail/exceptions.hpp>
#include <nlohmann/detail/iterators/internal_iterator.hpp> #include <nlohmann/detail/iterators/internal_iterator.hpp>
#include <nlohmann/detail/iterators/primitive_iterator.hpp> #include <nlohmann/detail/iterators/primitive_iterator.hpp>
@@ -85,7 +84,7 @@ class iter_impl
*/ */
explicit iter_impl(pointer object) noexcept : m_object(object) explicit iter_impl(pointer object) noexcept : m_object(object)
{ {
assert(m_object != nullptr); JSON_ASSERT(m_object != nullptr);
switch (m_object->m_type) switch (m_object->m_type)
{ {
@@ -171,7 +170,7 @@ class iter_impl
*/ */
void set_begin() noexcept void set_begin() noexcept
{ {
assert(m_object != nullptr); JSON_ASSERT(m_object != nullptr);
switch (m_object->m_type) switch (m_object->m_type)
{ {
@@ -208,7 +207,7 @@ class iter_impl
*/ */
void set_end() noexcept void set_end() noexcept
{ {
assert(m_object != nullptr); JSON_ASSERT(m_object != nullptr);
switch (m_object->m_type) switch (m_object->m_type)
{ {
@@ -239,19 +238,19 @@ class iter_impl
*/ */
reference operator*() const reference operator*() const
{ {
assert(m_object != nullptr); JSON_ASSERT(m_object != nullptr);
switch (m_object->m_type) switch (m_object->m_type)
{ {
case value_t::object: case value_t::object:
{ {
assert(m_it.object_iterator != m_object->m_value.object->end()); JSON_ASSERT(m_it.object_iterator != m_object->m_value.object->end());
return m_it.object_iterator->second; return m_it.object_iterator->second;
} }
case value_t::array: case value_t::array:
{ {
assert(m_it.array_iterator != m_object->m_value.array->end()); JSON_ASSERT(m_it.array_iterator != m_object->m_value.array->end());
return *m_it.array_iterator; return *m_it.array_iterator;
} }
@@ -276,19 +275,19 @@ class iter_impl
*/ */
pointer operator->() const pointer operator->() const
{ {
assert(m_object != nullptr); JSON_ASSERT(m_object != nullptr);
switch (m_object->m_type) switch (m_object->m_type)
{ {
case value_t::object: case value_t::object:
{ {
assert(m_it.object_iterator != m_object->m_value.object->end()); JSON_ASSERT(m_it.object_iterator != m_object->m_value.object->end());
return &(m_it.object_iterator->second); return &(m_it.object_iterator->second);
} }
case value_t::array: case value_t::array:
{ {
assert(m_it.array_iterator != m_object->m_value.array->end()); JSON_ASSERT(m_it.array_iterator != m_object->m_value.array->end());
return &*m_it.array_iterator; return &*m_it.array_iterator;
} }
@@ -321,7 +320,7 @@ class iter_impl
*/ */
iter_impl& operator++() iter_impl& operator++()
{ {
assert(m_object != nullptr); JSON_ASSERT(m_object != nullptr);
switch (m_object->m_type) switch (m_object->m_type)
{ {
@@ -364,7 +363,7 @@ class iter_impl
*/ */
iter_impl& operator--() iter_impl& operator--()
{ {
assert(m_object != nullptr); JSON_ASSERT(m_object != nullptr);
switch (m_object->m_type) switch (m_object->m_type)
{ {
@@ -402,7 +401,7 @@ class iter_impl
JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers")); JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers"));
} }
assert(m_object != nullptr); JSON_ASSERT(m_object != nullptr);
switch (m_object->m_type) switch (m_object->m_type)
{ {
@@ -423,7 +422,7 @@ class iter_impl
*/ */
bool operator!=(const iter_impl& other) const bool operator!=(const iter_impl& other) const
{ {
return not operator==(other); return !operator==(other);
} }
/*! /*!
@@ -438,7 +437,7 @@ class iter_impl
JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers")); JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers"));
} }
assert(m_object != nullptr); JSON_ASSERT(m_object != nullptr);
switch (m_object->m_type) switch (m_object->m_type)
{ {
@@ -459,7 +458,7 @@ class iter_impl
*/ */
bool operator<=(const iter_impl& other) const bool operator<=(const iter_impl& other) const
{ {
return not other.operator < (*this); return !other.operator < (*this);
} }
/*! /*!
@@ -468,7 +467,7 @@ class iter_impl
*/ */
bool operator>(const iter_impl& other) const bool operator>(const iter_impl& other) const
{ {
return not operator<=(other); return !operator<=(other);
} }
/*! /*!
@@ -477,7 +476,7 @@ class iter_impl
*/ */
bool operator>=(const iter_impl& other) const bool operator>=(const iter_impl& other) const
{ {
return not operator<(other); return !operator<(other);
} }
/*! /*!
@@ -486,7 +485,7 @@ class iter_impl
*/ */
iter_impl& operator+=(difference_type i) iter_impl& operator+=(difference_type i)
{ {
assert(m_object != nullptr); JSON_ASSERT(m_object != nullptr);
switch (m_object->m_type) switch (m_object->m_type)
{ {
@@ -557,7 +556,7 @@ class iter_impl
*/ */
difference_type operator-(const iter_impl& other) const difference_type operator-(const iter_impl& other) const
{ {
assert(m_object != nullptr); JSON_ASSERT(m_object != nullptr);
switch (m_object->m_type) switch (m_object->m_type)
{ {
@@ -578,7 +577,7 @@ class iter_impl
*/ */
reference operator[](difference_type n) const reference operator[](difference_type n) const
{ {
assert(m_object != nullptr); JSON_ASSERT(m_object != nullptr);
switch (m_object->m_type) switch (m_object->m_type)
{ {
@@ -609,7 +608,7 @@ class iter_impl
*/ */
const typename object_t::key_type& key() const const typename object_t::key_type& key() const
{ {
assert(m_object != nullptr); JSON_ASSERT(m_object != nullptr);
if (JSON_HEDLEY_LIKELY(m_object->is_object())) if (JSON_HEDLEY_LIKELY(m_object->is_object()))
{ {
@@ -15,7 +15,9 @@ namespace detail
template<typename string_type> template<typename string_type>
void int_to_string( string_type& target, std::size_t value ) void int_to_string( string_type& target, std::size_t value )
{ {
target = std::to_string(value); // For ADL
using std::to_string;
target = to_string(value);
} }
template<typename IteratorType> class iteration_proxy_value template<typename IteratorType> class iteration_proxy_value
{ {
@@ -72,7 +74,7 @@ template <typename IteratorType> class iteration_proxy_value
/// return key of the iterator /// return key of the iterator
const string_type& key() const const string_type& key() const
{ {
assert(anchor.m_object != nullptr); JSON_ASSERT(anchor.m_object != nullptr);
switch (anchor.m_object->type()) switch (anchor.m_object->type())
{ {
+37 -33
View File
@@ -1,8 +1,8 @@
#pragma once #pragma once
#include <algorithm> // all_of #include <algorithm> // all_of
#include <cassert> // assert
#include <cctype> // isdigit #include <cctype> // isdigit
#include <limits> // max
#include <numeric> // accumulate #include <numeric> // accumulate
#include <string> // string #include <string> // string
#include <utility> // move #include <utility> // move
@@ -325,12 +325,17 @@ class json_pointer
@return integer representation of @a s @return integer representation of @a s
@throw parse_error.106 if an array index begins with '0'
@throw parse_error.109 if an array index begins not with a digit
@throw out_of_range.404 if string @a s could not be converted to an integer @throw out_of_range.404 if string @a s could not be converted to an integer
@throw out_of_range.410 if an array index exceeds size_type
*/ */
static int array_index(const std::string& s) static typename BasicJsonType::size_type array_index(const std::string& s)
{ {
using size_type = typename BasicJsonType::size_type;
// error condition (cf. RFC 6901, Sect. 4) // error condition (cf. RFC 6901, Sect. 4)
if (JSON_HEDLEY_UNLIKELY(s.size() > 1 and s[0] == '0')) if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && s[0] == '0'))
{ {
JSON_THROW(detail::parse_error::create(106, 0, JSON_THROW(detail::parse_error::create(106, 0,
"array index '" + s + "array index '" + s +
@@ -338,16 +343,16 @@ class json_pointer
} }
// error condition (cf. RFC 6901, Sect. 4) // error condition (cf. RFC 6901, Sect. 4)
if (JSON_HEDLEY_UNLIKELY(s.size() > 1 and not (s[0] >= '1' and s[0] <= '9'))) if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && !(s[0] >= '1' && s[0] <= '9')))
{ {
JSON_THROW(detail::parse_error::create(109, 0, "array index '" + s + "' is not a number")); JSON_THROW(detail::parse_error::create(109, 0, "array index '" + s + "' is not a number"));
} }
std::size_t processed_chars = 0; std::size_t processed_chars = 0;
int res = 0; unsigned long long res = 0;
JSON_TRY JSON_TRY
{ {
res = std::stoi(s, &processed_chars); res = std::stoull(s, &processed_chars);
} }
JSON_CATCH(std::out_of_range&) JSON_CATCH(std::out_of_range&)
{ {
@@ -360,7 +365,14 @@ class json_pointer
JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + s + "'")); JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + s + "'"));
} }
return res; // only triggered on special platforms (like 32bit), see also
// https://github.com/nlohmann/json/pull/2203
if (res >= static_cast<unsigned long long>((std::numeric_limits<size_type>::max)()))
{
JSON_THROW(detail::out_of_range::create(410, "array index " + s + " exceeds size_type")); // LCOV_EXCL_LINE
}
return static_cast<size_type>(res);
} }
json_pointer top() const json_pointer top() const
@@ -385,7 +397,6 @@ class json_pointer
*/ */
BasicJsonType& get_and_create(BasicJsonType& j) const BasicJsonType& get_and_create(BasicJsonType& j) const
{ {
using size_type = typename BasicJsonType::size_type;
auto result = &j; auto result = &j;
// in case no reference tokens exist, return a reference to the JSON value // in case no reference tokens exist, return a reference to the JSON value
@@ -419,7 +430,7 @@ class json_pointer
case detail::value_t::array: case detail::value_t::array:
{ {
// create an entry in the array // create an entry in the array
result = &result->operator[](static_cast<size_type>(array_index(reference_token))); result = &result->operator[](array_index(reference_token));
break; break;
} }
@@ -458,7 +469,6 @@ class json_pointer
*/ */
BasicJsonType& get_unchecked(BasicJsonType* ptr) const BasicJsonType& get_unchecked(BasicJsonType* ptr) const
{ {
using size_type = typename BasicJsonType::size_type;
for (const auto& reference_token : reference_tokens) for (const auto& reference_token : reference_tokens)
{ {
// convert null values to arrays or objects before continuing // convert null values to arrays or objects before continuing
@@ -473,7 +483,7 @@ class json_pointer
}); });
// change value to array for numbers or "-" or to object otherwise // change value to array for numbers or "-" or to object otherwise
*ptr = (nums or reference_token == "-") *ptr = (nums || reference_token == "-")
? detail::value_t::array ? detail::value_t::array
: detail::value_t::object; : detail::value_t::object;
} }
@@ -497,8 +507,7 @@ class json_pointer
else else
{ {
// convert array index to number; unchecked access // convert array index to number; unchecked access
ptr = &ptr->operator[]( ptr = &ptr->operator[](array_index(reference_token));
static_cast<size_type>(array_index(reference_token)));
} }
break; break;
} }
@@ -519,7 +528,6 @@ class json_pointer
*/ */
BasicJsonType& get_checked(BasicJsonType* ptr) const BasicJsonType& get_checked(BasicJsonType* ptr) const
{ {
using size_type = typename BasicJsonType::size_type;
for (const auto& reference_token : reference_tokens) for (const auto& reference_token : reference_tokens)
{ {
switch (ptr->type()) switch (ptr->type())
@@ -542,7 +550,7 @@ class json_pointer
} }
// note: at performs range check // note: at performs range check
ptr = &ptr->at(static_cast<size_type>(array_index(reference_token))); ptr = &ptr->at(array_index(reference_token));
break; break;
} }
@@ -569,7 +577,6 @@ class json_pointer
*/ */
const BasicJsonType& get_unchecked(const BasicJsonType* ptr) const const BasicJsonType& get_unchecked(const BasicJsonType* ptr) const
{ {
using size_type = typename BasicJsonType::size_type;
for (const auto& reference_token : reference_tokens) for (const auto& reference_token : reference_tokens)
{ {
switch (ptr->type()) switch (ptr->type())
@@ -592,8 +599,7 @@ class json_pointer
} }
// use unchecked array access // use unchecked array access
ptr = &ptr->operator[]( ptr = &ptr->operator[](array_index(reference_token));
static_cast<size_type>(array_index(reference_token)));
break; break;
} }
@@ -613,7 +619,6 @@ class json_pointer
*/ */
const BasicJsonType& get_checked(const BasicJsonType* ptr) const const BasicJsonType& get_checked(const BasicJsonType* ptr) const
{ {
using size_type = typename BasicJsonType::size_type;
for (const auto& reference_token : reference_tokens) for (const auto& reference_token : reference_tokens)
{ {
switch (ptr->type()) switch (ptr->type())
@@ -636,7 +641,7 @@ class json_pointer
} }
// note: at performs range check // note: at performs range check
ptr = &ptr->at(static_cast<size_type>(array_index(reference_token))); ptr = &ptr->at(array_index(reference_token));
break; break;
} }
@@ -654,14 +659,13 @@ class json_pointer
*/ */
bool contains(const BasicJsonType* ptr) const bool contains(const BasicJsonType* ptr) const
{ {
using size_type = typename BasicJsonType::size_type;
for (const auto& reference_token : reference_tokens) for (const auto& reference_token : reference_tokens)
{ {
switch (ptr->type()) switch (ptr->type())
{ {
case detail::value_t::object: case detail::value_t::object:
{ {
if (not ptr->contains(reference_token)) if (!ptr->contains(reference_token))
{ {
// we did not find the key in the object // we did not find the key in the object
return false; return false;
@@ -678,21 +682,21 @@ class json_pointer
// "-" always fails the range check // "-" always fails the range check
return false; return false;
} }
if (JSON_HEDLEY_UNLIKELY(reference_token.size() == 1 and not ("0" <= reference_token and reference_token <= "9"))) if (JSON_HEDLEY_UNLIKELY(reference_token.size() == 1 && !("0" <= reference_token && reference_token <= "9")))
{ {
// invalid char // invalid char
return false; return false;
} }
if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1)) if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1))
{ {
if (JSON_HEDLEY_UNLIKELY(not ('1' <= reference_token[0] and reference_token[0] <= '9'))) if (JSON_HEDLEY_UNLIKELY(!('1' <= reference_token[0] && reference_token[0] <= '9')))
{ {
// first char should be between '1' and '9' // first char should be between '1' and '9'
return false; return false;
} }
for (std::size_t i = 1; i < reference_token.size(); i++) for (std::size_t i = 1; i < reference_token.size(); i++)
{ {
if (JSON_HEDLEY_UNLIKELY(not ('0' <= reference_token[i] and reference_token[i] <= '9'))) if (JSON_HEDLEY_UNLIKELY(!('0' <= reference_token[i] && reference_token[i] <= '9')))
{ {
// other char should be between '0' and '9' // other char should be between '0' and '9'
return false; return false;
@@ -700,7 +704,7 @@ class json_pointer
} }
} }
const auto idx = static_cast<size_type>(array_index(reference_token)); const auto idx = array_index(reference_token);
if (idx >= ptr->size()) if (idx >= ptr->size())
{ {
// index out of range // index out of range
@@ -776,11 +780,11 @@ class json_pointer
pos != std::string::npos; pos != std::string::npos;
pos = reference_token.find_first_of('~', pos + 1)) pos = reference_token.find_first_of('~', pos + 1))
{ {
assert(reference_token[pos] == '~'); JSON_ASSERT(reference_token[pos] == '~');
// ~ must be followed by 0 or 1 // ~ must be followed by 0 or 1
if (JSON_HEDLEY_UNLIKELY(pos == reference_token.size() - 1 or if (JSON_HEDLEY_UNLIKELY(pos == reference_token.size() - 1 ||
(reference_token[pos + 1] != '0' and (reference_token[pos + 1] != '0' &&
reference_token[pos + 1] != '1'))) reference_token[pos + 1] != '1')))
{ {
JSON_THROW(detail::parse_error::create(108, 0, "escape character '~' must be followed with '0' or '1'")); JSON_THROW(detail::parse_error::create(108, 0, "escape character '~' must be followed with '0' or '1'"));
@@ -811,7 +815,7 @@ class json_pointer
static void replace_substring(std::string& s, const std::string& f, static void replace_substring(std::string& s, const std::string& f,
const std::string& t) const std::string& t)
{ {
assert(not f.empty()); JSON_ASSERT(!f.empty());
for (auto pos = s.find(f); // find first occurrence of f for (auto pos = s.find(f); // find first occurrence of f
pos != std::string::npos; // make sure f was found pos != std::string::npos; // make sure f was found
s.replace(pos, f.size(), t), // replace with t, and s.replace(pos, f.size(), t), // replace with t, and
@@ -906,7 +910,7 @@ class json_pointer
static BasicJsonType static BasicJsonType
unflatten(const BasicJsonType& value) unflatten(const BasicJsonType& value)
{ {
if (JSON_HEDLEY_UNLIKELY(not value.is_object())) if (JSON_HEDLEY_UNLIKELY(!value.is_object()))
{ {
JSON_THROW(detail::type_error::create(314, "only objects can be unflattened")); JSON_THROW(detail::type_error::create(314, "only objects can be unflattened"));
} }
@@ -916,7 +920,7 @@ class json_pointer
// iterate the JSON object values // iterate the JSON object values
for (const auto& element : *value.m_value.object) for (const auto& element : *value.m_value.object)
{ {
if (JSON_HEDLEY_UNLIKELY(not element.second.is_primitive())) if (JSON_HEDLEY_UNLIKELY(!element.second.is_primitive()))
{ {
JSON_THROW(detail::type_error::create(315, "values in object must be primitive")); JSON_THROW(detail::type_error::create(315, "values in object must be primitive"));
} }
@@ -962,7 +966,7 @@ class json_pointer
friend bool operator!=(json_pointer const& lhs, friend bool operator!=(json_pointer const& lhs,
json_pointer const& rhs) noexcept json_pointer const& rhs) noexcept
{ {
return not (lhs == rhs); return !(lhs == rhs);
} }
/// the reference tokens /// the reference tokens
+13 -6
View File
@@ -16,23 +16,30 @@ class json_ref
using value_type = BasicJsonType; using value_type = BasicJsonType;
json_ref(value_type&& value) json_ref(value_type&& value)
: owned_value(std::move(value)), value_ref(&owned_value), is_rvalue(true) : owned_value(std::move(value))
, value_ref(&owned_value)
, is_rvalue(true)
{} {}
json_ref(const value_type& value) json_ref(const value_type& value)
: value_ref(const_cast<value_type*>(&value)), is_rvalue(false) : value_ref(const_cast<value_type*>(&value))
, is_rvalue(false)
{} {}
json_ref(std::initializer_list<json_ref> init) json_ref(std::initializer_list<json_ref> init)
: owned_value(init), value_ref(&owned_value), is_rvalue(true) : owned_value(init)
, value_ref(&owned_value)
, is_rvalue(true)
{} {}
template < template <
class... Args, class... Args,
enable_if_t<std::is_constructible<value_type, Args...>::value, int> = 0 > enable_if_t<std::is_constructible<value_type, Args...>::value, int> = 0 >
json_ref(Args && ... args) json_ref(Args && ... args)
: owned_value(std::forward<Args>(args)...), value_ref(&owned_value), : owned_value(std::forward<Args>(args)...)
is_rvalue(true) {} , value_ref(&owned_value)
, is_rvalue(true)
{}
// class should be movable only // class should be movable only
json_ref(json_ref&&) = default; json_ref(json_ref&&) = default;
@@ -63,7 +70,7 @@ class json_ref
private: private:
mutable value_type owned_value = nullptr; mutable value_type owned_value = nullptr;
value_type* value_ref = nullptr; value_type* value_ref = nullptr;
const bool is_rvalue; const bool is_rvalue = true;
}; };
} // namespace detail } // namespace detail
} // namespace nlohmann } // namespace nlohmann
+52 -1
View File
@@ -20,7 +20,11 @@
#endif #endif
// C++ language standard detection // C++ language standard detection
#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 #if (defined(__cplusplus) && __cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)
#define JSON_HAS_CPP_20
#define JSON_HAS_CPP_17
#define JSON_HAS_CPP_14
#elif (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464
#define JSON_HAS_CPP_17 #define JSON_HAS_CPP_17
#define JSON_HAS_CPP_14 #define JSON_HAS_CPP_14
#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) #elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1)
@@ -73,6 +77,12 @@
#define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER
#endif #endif
// allow to override assert
#if !defined(JSON_ASSERT)
#include <cassert> // assert
#define JSON_ASSERT(x) assert(x)
#endif
/*! /*!
@brief macro to briefly define a mapping between an enum and JSON @brief macro to briefly define a mapping between an enum and JSON
@def NLOHMANN_JSON_SERIALIZE_ENUM @def NLOHMANN_JSON_SERIALIZE_ENUM
@@ -120,3 +130,44 @@
basic_json<ObjectType, ArrayType, StringType, BooleanType, \ basic_json<ObjectType, ArrayType, StringType, BooleanType, \
NumberIntegerType, NumberUnsignedType, NumberFloatType, \ NumberIntegerType, NumberUnsignedType, NumberFloatType, \
AllocatorType, JSONSerializer, BinaryType> AllocatorType, JSONSerializer, BinaryType>
// Macros to simplify conversion from/to types
#define NLOHMANN_JSON_EXPAND( x ) x
#define NLOHMANN_JSON_GET_MACRO(_1,_2,_3,_4,_5,_6, _7, _8, _9, _10, _11, NAME,...) NAME
#define NLOHMANN_JSON_PASTE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_GET_MACRO(__VA_ARGS__, NLOHMANN_JSON_PASTE11, \
NLOHMANN_JSON_PASTE10, NLOHMANN_JSON_PASTE9, NLOHMANN_JSON_PASTE8, NLOHMANN_JSON_PASTE7, \
NLOHMANN_JSON_PASTE6, NLOHMANN_JSON_PASTE5, NLOHMANN_JSON_PASTE4, NLOHMANN_JSON_PASTE3, \
NLOHMANN_JSON_PASTE2, NLOHMANN_JSON_PASTE1)(__VA_ARGS__))
#define NLOHMANN_JSON_PASTE2(func, v1) func(v1)
#define NLOHMANN_JSON_PASTE3(func, v1, v2) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE2(func, v2)
#define NLOHMANN_JSON_PASTE4(func, v1, v2, v3) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE3(func, v2, v3)
#define NLOHMANN_JSON_PASTE5(func, v1, v2, v3, v4) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE4(func, v2, v3, v4)
#define NLOHMANN_JSON_PASTE6(func, v1, v2, v3, v4, v5) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE5(func, v2, v3, v4, v5)
#define NLOHMANN_JSON_PASTE7(func, v1, v2, v3, v4, v5, v6) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE6(func, v2, v3, v4, v5, v6)
#define NLOHMANN_JSON_PASTE8(func, v1, v2, v3, v4, v5, v6, v7) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE7(func, v2, v3, v4, v5, v6, v7)
#define NLOHMANN_JSON_PASTE9(func, v1, v2, v3, v4, v5, v6, v7, v8) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE8(func, v2, v3, v4, v5, v6, v7, v8)
#define NLOHMANN_JSON_PASTE10(func, v1, v2, v3, v4, v5, v6, v7, v8, v9) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE8(func, v2, v3, v4, v5, v6, v7, v8, v9)
#define NLOHMANN_JSON_PASTE11(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE8(func, v2, v3, v4, v5, v6, v7, v8, v9, v10)
#define NLOHMANN_JSON_TO(v1) j[#v1] = t.v1;
#define NLOHMANN_JSON_FROM(v1) j.at(#v1).get_to(t.v1);
/*!
@brief macro
@def NLOHMANN_DEFINE_TYPE_INTRUSIVE
@since version 3.9.0
*/
#define NLOHMANN_DEFINE_TYPE_INTRUSIVE(Type, ...) \
friend void to_json(nlohmann::json& j, const Type& t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
friend void from_json(const nlohmann::json& j, Type& t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }
/*!
@brief macro
@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE
@since version 3.9.0
*/
#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Type, ...) \
void to_json(nlohmann::json& j, const Type& t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
void from_json(const nlohmann::json& j, Type& t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }
@@ -9,6 +9,7 @@
#endif #endif
// clean up // clean up
#undef JSON_ASSERT
#undef JSON_INTERNAL_CATCH #undef JSON_INTERNAL_CATCH
#undef JSON_CATCH #undef JSON_CATCH
#undef JSON_THROW #undef JSON_THROW
@@ -3,8 +3,6 @@
#include <cstddef> // size_t #include <cstddef> // size_t
#include <type_traits> // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type #include <type_traits> // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type
#include <nlohmann/detail/boolean_operators.hpp>
namespace nlohmann namespace nlohmann
{ {
namespace detail namespace detail
+50 -31
View File
@@ -4,7 +4,6 @@
#include <type_traits> // false_type, is_constructible, is_integral, is_same, true_type #include <type_traits> // false_type, is_constructible, is_integral, is_same, true_type
#include <utility> // declval #include <utility> // declval
#include <nlohmann/detail/boolean_operators.hpp>
#include <nlohmann/detail/iterators/iterator_traits.hpp> #include <nlohmann/detail/iterators/iterator_traits.hpp>
#include <nlohmann/detail/macro_scope.hpp> #include <nlohmann/detail/macro_scope.hpp>
#include <nlohmann/detail/meta/cpp_future.hpp> #include <nlohmann/detail/meta/cpp_future.hpp>
@@ -97,7 +96,7 @@ struct has_from_json : std::false_type {};
template<typename BasicJsonType, typename T> template<typename BasicJsonType, typename T>
struct has_from_json < BasicJsonType, T, struct has_from_json < BasicJsonType, T,
enable_if_t<not is_basic_json<T>::value>> enable_if_t < !is_basic_json<T>::value >>
{ {
using serializer = typename BasicJsonType::template json_serializer<T, void>; using serializer = typename BasicJsonType::template json_serializer<T, void>;
@@ -112,7 +111,7 @@ template <typename BasicJsonType, typename T, typename = void>
struct has_non_default_from_json : std::false_type {}; struct has_non_default_from_json : std::false_type {};
template<typename BasicJsonType, typename T> template<typename BasicJsonType, typename T>
struct has_non_default_from_json<BasicJsonType, T, enable_if_t<not is_basic_json<T>::value>> struct has_non_default_from_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >>
{ {
using serializer = typename BasicJsonType::template json_serializer<T, void>; using serializer = typename BasicJsonType::template json_serializer<T, void>;
@@ -127,7 +126,7 @@ template <typename BasicJsonType, typename T, typename = void>
struct has_to_json : std::false_type {}; struct has_to_json : std::false_type {};
template<typename BasicJsonType, typename T> template<typename BasicJsonType, typename T>
struct has_to_json<BasicJsonType, T, enable_if_t<not is_basic_json<T>::value>> struct has_to_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >>
{ {
using serializer = typename BasicJsonType::template json_serializer<T, void>; using serializer = typename BasicJsonType::template json_serializer<T, void>;
@@ -174,7 +173,7 @@ struct is_compatible_object_type_impl : std::false_type {};
template<typename BasicJsonType, typename CompatibleObjectType> template<typename BasicJsonType, typename CompatibleObjectType>
struct is_compatible_object_type_impl < struct is_compatible_object_type_impl <
BasicJsonType, CompatibleObjectType, BasicJsonType, CompatibleObjectType,
enable_if_t<is_detected<mapped_type_t, CompatibleObjectType>::value and enable_if_t < is_detected<mapped_type_t, CompatibleObjectType>::value&&
is_detected<key_type_t, CompatibleObjectType>::value >> is_detected<key_type_t, CompatibleObjectType>::value >>
{ {
@@ -183,7 +182,7 @@ struct is_compatible_object_type_impl <
// macOS's is_constructible does not play well with nonesuch... // macOS's is_constructible does not play well with nonesuch...
static constexpr bool value = static constexpr bool value =
std::is_constructible<typename object_t::key_type, std::is_constructible<typename object_t::key_type,
typename CompatibleObjectType::key_type>::value and typename CompatibleObjectType::key_type>::value &&
std::is_constructible<typename object_t::mapped_type, std::is_constructible<typename object_t::mapped_type,
typename CompatibleObjectType::mapped_type>::value; typename CompatibleObjectType::mapped_type>::value;
}; };
@@ -199,22 +198,22 @@ struct is_constructible_object_type_impl : std::false_type {};
template<typename BasicJsonType, typename ConstructibleObjectType> template<typename BasicJsonType, typename ConstructibleObjectType>
struct is_constructible_object_type_impl < struct is_constructible_object_type_impl <
BasicJsonType, ConstructibleObjectType, BasicJsonType, ConstructibleObjectType,
enable_if_t<is_detected<mapped_type_t, ConstructibleObjectType>::value and enable_if_t < is_detected<mapped_type_t, ConstructibleObjectType>::value&&
is_detected<key_type_t, ConstructibleObjectType>::value >> is_detected<key_type_t, ConstructibleObjectType>::value >>
{ {
using object_t = typename BasicJsonType::object_t; using object_t = typename BasicJsonType::object_t;
static constexpr bool value = static constexpr bool value =
(std::is_default_constructible<ConstructibleObjectType>::value and (std::is_default_constructible<ConstructibleObjectType>::value &&
(std::is_move_assignable<ConstructibleObjectType>::value or (std::is_move_assignable<ConstructibleObjectType>::value ||
std::is_copy_assignable<ConstructibleObjectType>::value) and std::is_copy_assignable<ConstructibleObjectType>::value) &&
(std::is_constructible<typename ConstructibleObjectType::key_type, (std::is_constructible<typename ConstructibleObjectType::key_type,
typename object_t::key_type>::value and typename object_t::key_type>::value &&
std::is_same < std::is_same <
typename object_t::mapped_type, typename object_t::mapped_type,
typename ConstructibleObjectType::mapped_type >::value)) or typename ConstructibleObjectType::mapped_type >::value)) ||
(has_from_json<BasicJsonType, (has_from_json<BasicJsonType,
typename ConstructibleObjectType::mapped_type>::value or typename ConstructibleObjectType::mapped_type>::value ||
has_non_default_from_json < has_non_default_from_json <
BasicJsonType, BasicJsonType,
typename ConstructibleObjectType::mapped_type >::value); typename ConstructibleObjectType::mapped_type >::value);
@@ -268,12 +267,12 @@ struct is_compatible_array_type_impl : std::false_type {};
template<typename BasicJsonType, typename CompatibleArrayType> template<typename BasicJsonType, typename CompatibleArrayType>
struct is_compatible_array_type_impl < struct is_compatible_array_type_impl <
BasicJsonType, CompatibleArrayType, BasicJsonType, CompatibleArrayType,
enable_if_t<is_detected<value_type_t, CompatibleArrayType>::value and enable_if_t < is_detected<value_type_t, CompatibleArrayType>::value&&
is_detected<iterator_t, CompatibleArrayType>::value and is_detected<iterator_t, CompatibleArrayType>::value&&
// This is needed because json_reverse_iterator has a ::iterator type... // This is needed because json_reverse_iterator has a ::iterator type...
// Therefore it is detected as a CompatibleArrayType. // Therefore it is detected as a CompatibleArrayType.
// The real fix would be to have an Iterable concept. // The real fix would be to have an Iterable concept.
not is_iterator_traits< !is_iterator_traits <
iterator_traits<CompatibleArrayType >>::value >> iterator_traits<CompatibleArrayType >>::value >>
{ {
static constexpr bool value = static constexpr bool value =
@@ -298,13 +297,13 @@ struct is_constructible_array_type_impl <
template<typename BasicJsonType, typename ConstructibleArrayType> template<typename BasicJsonType, typename ConstructibleArrayType>
struct is_constructible_array_type_impl < struct is_constructible_array_type_impl <
BasicJsonType, ConstructibleArrayType, BasicJsonType, ConstructibleArrayType,
enable_if_t<not std::is_same<ConstructibleArrayType, enable_if_t < !std::is_same<ConstructibleArrayType,
typename BasicJsonType::value_type>::value and typename BasicJsonType::value_type>::value&&
std::is_default_constructible<ConstructibleArrayType>::value and std::is_default_constructible<ConstructibleArrayType>::value&&
(std::is_move_assignable<ConstructibleArrayType>::value or (std::is_move_assignable<ConstructibleArrayType>::value ||
std::is_copy_assignable<ConstructibleArrayType>::value) and std::is_copy_assignable<ConstructibleArrayType>::value)&&
is_detected<value_type_t, ConstructibleArrayType>::value and is_detected<value_type_t, ConstructibleArrayType>::value&&
is_detected<iterator_t, ConstructibleArrayType>::value and is_detected<iterator_t, ConstructibleArrayType>::value&&
is_complete_type < is_complete_type <
detected_t<value_type_t, ConstructibleArrayType >>::value >> detected_t<value_type_t, ConstructibleArrayType >>::value >>
{ {
@@ -314,12 +313,12 @@ detected_t<value_type_t, ConstructibleArrayType>>::value >>
// base class `iterator`... Therefore it is detected as a // base class `iterator`... Therefore it is detected as a
// ConstructibleArrayType. The real fix would be to have an Iterable // ConstructibleArrayType. The real fix would be to have an Iterable
// concept. // concept.
not is_iterator_traits<iterator_traits<ConstructibleArrayType>>::value and !is_iterator_traits<iterator_traits<ConstructibleArrayType>>::value &&
(std::is_same<typename ConstructibleArrayType::value_type, (std::is_same<typename ConstructibleArrayType::value_type,
typename BasicJsonType::array_t::value_type>::value or typename BasicJsonType::array_t::value_type>::value ||
has_from_json<BasicJsonType, has_from_json<BasicJsonType,
typename ConstructibleArrayType::value_type>::value or typename ConstructibleArrayType::value_type>::value ||
has_non_default_from_json < has_non_default_from_json <
BasicJsonType, typename ConstructibleArrayType::value_type >::value); BasicJsonType, typename ConstructibleArrayType::value_type >::value);
}; };
@@ -328,6 +327,16 @@ template <typename BasicJsonType, typename ConstructibleArrayType>
struct is_constructible_array_type struct is_constructible_array_type
: is_constructible_array_type_impl<BasicJsonType, ConstructibleArrayType> {}; : is_constructible_array_type_impl<BasicJsonType, ConstructibleArrayType> {};
// true for types with up to 64 bit
template<typename NumberType>
struct is_64_bit : std::integral_constant < bool, (sizeof(NumberType) <= 8) >
{};
// true for types with at least 64 bit that con be convert from 64 bit integers
template<typename NumberType>
struct is_128_bit_integral : std::integral_constant < bool, (((std::is_signed<NumberType>::value&& std::is_convertible<std::int64_t, NumberType>::value) || (std::is_unsigned<NumberType>::value&& std::is_convertible<std::uint64_t, NumberType>::value))&& !is_64_bit<NumberType>::value) >
{};
template<typename RealIntegerType, typename CompatibleNumberIntegerType, template<typename RealIntegerType, typename CompatibleNumberIntegerType,
typename = void> typename = void>
struct is_compatible_integer_type_impl : std::false_type {}; struct is_compatible_integer_type_impl : std::false_type {};
@@ -335,9 +344,9 @@ struct is_compatible_integer_type_impl : std::false_type {};
template<typename RealIntegerType, typename CompatibleNumberIntegerType> template<typename RealIntegerType, typename CompatibleNumberIntegerType>
struct is_compatible_integer_type_impl < struct is_compatible_integer_type_impl <
RealIntegerType, CompatibleNumberIntegerType, RealIntegerType, CompatibleNumberIntegerType,
enable_if_t<std::is_integral<RealIntegerType>::value and enable_if_t < std::is_integral<RealIntegerType>::value&&
std::is_integral<CompatibleNumberIntegerType>::value and std::is_integral<CompatibleNumberIntegerType>::value&&
not std::is_same<bool, CompatibleNumberIntegerType>::value >> !std::is_same<bool, CompatibleNumberIntegerType>::value >>
{ {
// is there an assert somewhere on overflows? // is there an assert somewhere on overflows?
using RealLimits = std::numeric_limits<RealIntegerType>; using RealLimits = std::numeric_limits<RealIntegerType>;
@@ -345,11 +354,21 @@ struct is_compatible_integer_type_impl <
static constexpr auto value = static constexpr auto value =
std::is_constructible<RealIntegerType, std::is_constructible<RealIntegerType,
CompatibleNumberIntegerType>::value and CompatibleNumberIntegerType>::value &&
CompatibleLimits::is_integer and CompatibleLimits::is_integer &&
RealLimits::is_signed == CompatibleLimits::is_signed; RealLimits::is_signed == CompatibleLimits::is_signed;
}; };
// second version for 128 bit integers that fail std::is_integral test
template<typename RealIntegerType, typename CompatibleNumberIntegerType>
struct is_compatible_integer_type_impl < RealIntegerType, CompatibleNumberIntegerType,
enable_if_t < std::is_same<RealIntegerType, CompatibleNumberIntegerType>::value&&
!std::is_integral<CompatibleNumberIntegerType>::value&&
is_128_bit_integral<CompatibleNumberIntegerType>::value >>
{
static constexpr auto value = true;
};
template<typename RealIntegerType, typename CompatibleNumberIntegerType> template<typename RealIntegerType, typename CompatibleNumberIntegerType>
struct is_compatible_integer_type struct is_compatible_integer_type
: is_compatible_integer_type_impl<RealIntegerType, : is_compatible_integer_type_impl<RealIntegerType,
@@ -28,6 +28,7 @@ class binary_writer
{ {
using string_t = typename BasicJsonType::string_t; using string_t = typename BasicJsonType::string_t;
using binary_t = typename BasicJsonType::binary_t; using binary_t = typename BasicJsonType::binary_t;
using number_float_t = typename BasicJsonType::number_float_t;
public: public:
/*! /*!
@@ -37,7 +38,7 @@ class binary_writer
*/ */
explicit binary_writer(output_adapter_t<CharType> adapter) : oa(adapter) explicit binary_writer(output_adapter_t<CharType> adapter) : oa(adapter)
{ {
assert(oa); JSON_ASSERT(oa);
} }
/*! /*!
@@ -194,18 +195,7 @@ class binary_writer
} }
else else
{ {
if (static_cast<double>(j.m_value.number_float) >= static_cast<double>(std::numeric_limits<float>::lowest()) and write_compact_float(j.m_value.number_float, detail::input_format_t::cbor);
static_cast<double>(j.m_value.number_float) <= static_cast<double>((std::numeric_limits<float>::max)()) and
static_cast<double>(static_cast<float>(j.m_value.number_float)) == static_cast<double>(j.m_value.number_float))
{
oa->write_character(get_cbor_float_prefix(static_cast<float>(j.m_value.number_float)));
write_number(static_cast<float>(j.m_value.number_float));
}
else
{
oa->write_character(get_cbor_float_prefix(j.m_value.number_float));
write_number(j.m_value.number_float);
}
} }
break; break;
} }
@@ -436,28 +426,28 @@ class binary_writer
// negative fixnum // negative fixnum
write_number(static_cast<std::int8_t>(j.m_value.number_integer)); write_number(static_cast<std::int8_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_integer >= (std::numeric_limits<std::int8_t>::min)() and else if (j.m_value.number_integer >= (std::numeric_limits<std::int8_t>::min)() &&
j.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)()) j.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)())
{ {
// int 8 // int 8
oa->write_character(to_char_type(0xD0)); oa->write_character(to_char_type(0xD0));
write_number(static_cast<std::int8_t>(j.m_value.number_integer)); write_number(static_cast<std::int8_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_integer >= (std::numeric_limits<std::int16_t>::min)() and else if (j.m_value.number_integer >= (std::numeric_limits<std::int16_t>::min)() &&
j.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)()) j.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)())
{ {
// int 16 // int 16
oa->write_character(to_char_type(0xD1)); oa->write_character(to_char_type(0xD1));
write_number(static_cast<std::int16_t>(j.m_value.number_integer)); write_number(static_cast<std::int16_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_integer >= (std::numeric_limits<std::int32_t>::min)() and else if (j.m_value.number_integer >= (std::numeric_limits<std::int32_t>::min)() &&
j.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)()) j.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)())
{ {
// int 32 // int 32
oa->write_character(to_char_type(0xD2)); oa->write_character(to_char_type(0xD2));
write_number(static_cast<std::int32_t>(j.m_value.number_integer)); write_number(static_cast<std::int32_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_integer >= (std::numeric_limits<std::int64_t>::min)() and else if (j.m_value.number_integer >= (std::numeric_limits<std::int64_t>::min)() &&
j.m_value.number_integer <= (std::numeric_limits<std::int64_t>::max)()) j.m_value.number_integer <= (std::numeric_limits<std::int64_t>::max)())
{ {
// int 64 // int 64
@@ -504,8 +494,7 @@ class binary_writer
case value_t::number_float: case value_t::number_float:
{ {
oa->write_character(get_msgpack_float_prefix(j.m_value.number_float)); write_compact_float(j.m_value.number_float, detail::input_format_t::msgpack);
write_number(j.m_value.number_float);
break; break;
} }
@@ -584,7 +573,7 @@ class binary_writer
const auto N = j.m_value.binary->size(); const auto N = j.m_value.binary->size();
if (N <= (std::numeric_limits<std::uint8_t>::max)()) if (N <= (std::numeric_limits<std::uint8_t>::max)())
{ {
std::uint8_t output_type; std::uint8_t output_type{};
bool fixed = true; bool fixed = true;
if (use_ext) if (use_ext)
{ {
@@ -619,37 +608,25 @@ class binary_writer
} }
oa->write_character(to_char_type(output_type)); oa->write_character(to_char_type(output_type));
if (not fixed) if (!fixed)
{ {
write_number(static_cast<std::uint8_t>(N)); write_number(static_cast<std::uint8_t>(N));
} }
} }
else if (N <= (std::numeric_limits<std::uint16_t>::max)()) else if (N <= (std::numeric_limits<std::uint16_t>::max)())
{ {
std::uint8_t output_type; std::uint8_t output_type = use_ext
if (use_ext) ? 0xC8 // ext 16
{ : 0xC5; // bin 16
output_type = 0xC8; // ext 16
}
else
{
output_type = 0xC5; // bin 16
}
oa->write_character(to_char_type(output_type)); oa->write_character(to_char_type(output_type));
write_number(static_cast<std::uint16_t>(N)); write_number(static_cast<std::uint16_t>(N));
} }
else if (N <= (std::numeric_limits<std::uint32_t>::max)()) else if (N <= (std::numeric_limits<std::uint32_t>::max)())
{ {
std::uint8_t output_type; std::uint8_t output_type = use_ext
if (use_ext) ? 0xC9 // ext 32
{ : 0xC6; // bin 32
output_type = 0xC9; // ext 32
}
else
{
output_type = 0xC6; // bin 32
}
oa->write_character(to_char_type(output_type)); oa->write_character(to_char_type(output_type));
write_number(static_cast<std::uint32_t>(N)); write_number(static_cast<std::uint32_t>(N));
@@ -775,9 +752,9 @@ class binary_writer
} }
bool prefix_required = true; bool prefix_required = true;
if (use_type and not j.m_value.array->empty()) if (use_type && !j.m_value.array->empty())
{ {
assert(use_count); JSON_ASSERT(use_count);
const CharType first_prefix = ubjson_prefix(j.front()); const CharType first_prefix = ubjson_prefix(j.front());
const bool same_prefix = std::all_of(j.begin() + 1, j.end(), const bool same_prefix = std::all_of(j.begin() + 1, j.end(),
[this, first_prefix](const BasicJsonType & v) [this, first_prefix](const BasicJsonType & v)
@@ -804,7 +781,7 @@ class binary_writer
write_ubjson(el, use_count, use_type, prefix_required); write_ubjson(el, use_count, use_type, prefix_required);
} }
if (not use_count) if (!use_count)
{ {
oa->write_character(to_char_type(']')); oa->write_character(to_char_type(']'));
} }
@@ -819,9 +796,9 @@ class binary_writer
oa->write_character(to_char_type('[')); oa->write_character(to_char_type('['));
} }
if (use_type and not j.m_value.binary->empty()) if (use_type && !j.m_value.binary->empty())
{ {
assert(use_count); JSON_ASSERT(use_count);
oa->write_character(to_char_type('$')); oa->write_character(to_char_type('$'));
oa->write_character('U'); oa->write_character('U');
} }
@@ -847,7 +824,7 @@ class binary_writer
} }
} }
if (not use_count) if (!use_count)
{ {
oa->write_character(to_char_type(']')); oa->write_character(to_char_type(']'));
} }
@@ -863,9 +840,9 @@ class binary_writer
} }
bool prefix_required = true; bool prefix_required = true;
if (use_type and not j.m_value.object->empty()) if (use_type && !j.m_value.object->empty())
{ {
assert(use_count); JSON_ASSERT(use_count);
const CharType first_prefix = ubjson_prefix(j.front()); const CharType first_prefix = ubjson_prefix(j.front());
const bool same_prefix = std::all_of(j.begin(), j.end(), const bool same_prefix = std::all_of(j.begin(), j.end(),
[this, first_prefix](const BasicJsonType & v) [this, first_prefix](const BasicJsonType & v)
@@ -896,7 +873,7 @@ class binary_writer
write_ubjson(el.second, use_count, use_type, prefix_required); write_ubjson(el.second, use_count, use_type, prefix_required);
} }
if (not use_count) if (!use_count)
{ {
oa->write_character(to_char_type('}')); oa->write_character(to_char_type('}'));
} }
@@ -997,7 +974,7 @@ class binary_writer
*/ */
static std::size_t calc_bson_integer_size(const std::int64_t value) static std::size_t calc_bson_integer_size(const std::int64_t value)
{ {
return (std::numeric_limits<std::int32_t>::min)() <= value and value <= (std::numeric_limits<std::int32_t>::max)() return (std::numeric_limits<std::int32_t>::min)() <= value && value <= (std::numeric_limits<std::int32_t>::max)()
? sizeof(std::int32_t) ? sizeof(std::int32_t)
: sizeof(std::int64_t); : sizeof(std::int64_t);
} }
@@ -1008,7 +985,7 @@ class binary_writer
void write_bson_integer(const string_t& name, void write_bson_integer(const string_t& name,
const std::int64_t value) const std::int64_t value)
{ {
if ((std::numeric_limits<std::int32_t>::min)() <= value and value <= (std::numeric_limits<std::int32_t>::max)()) if ((std::numeric_limits<std::int32_t>::min)() <= value && value <= (std::numeric_limits<std::int32_t>::max)())
{ {
write_bson_entry_header(name, 0x10); // int32 write_bson_entry_header(name, 0x10); // int32
write_number<std::int32_t, true>(static_cast<std::int32_t>(value)); write_number<std::int32_t, true>(static_cast<std::int32_t>(value));
@@ -1157,7 +1134,7 @@ class binary_writer
// LCOV_EXCL_START // LCOV_EXCL_START
default: default:
assert(false); JSON_ASSERT(false);
return 0ul; return 0ul;
// LCOV_EXCL_STOP // LCOV_EXCL_STOP
} }
@@ -1204,7 +1181,7 @@ class binary_writer
// LCOV_EXCL_START // LCOV_EXCL_START
default: default:
assert(false); JSON_ASSERT(false);
return; return;
// LCOV_EXCL_STOP // LCOV_EXCL_STOP
} }
@@ -1342,12 +1319,12 @@ class binary_writer
// UBJSON: write number (signed integer) // UBJSON: write number (signed integer)
template < typename NumberType, typename std::enable_if < template < typename NumberType, typename std::enable_if <
std::is_signed<NumberType>::value and std::is_signed<NumberType>::value&&
not std::is_floating_point<NumberType>::value, int>::type = 0> !std::is_floating_point<NumberType>::value, int >::type = 0 >
void write_number_with_ubjson_prefix(const NumberType n, void write_number_with_ubjson_prefix(const NumberType n,
const bool add_prefix) const bool add_prefix)
{ {
if ((std::numeric_limits<std::int8_t>::min)() <= n and n <= (std::numeric_limits<std::int8_t>::max)()) if ((std::numeric_limits<std::int8_t>::min)() <= n && n <= (std::numeric_limits<std::int8_t>::max)())
{ {
if (add_prefix) if (add_prefix)
{ {
@@ -1355,7 +1332,7 @@ class binary_writer
} }
write_number(static_cast<std::int8_t>(n)); write_number(static_cast<std::int8_t>(n));
} }
else if (static_cast<std::int64_t>((std::numeric_limits<std::uint8_t>::min)()) <= n and n <= static_cast<std::int64_t>((std::numeric_limits<std::uint8_t>::max)())) else if (static_cast<std::int64_t>((std::numeric_limits<std::uint8_t>::min)()) <= n && n <= static_cast<std::int64_t>((std::numeric_limits<std::uint8_t>::max)()))
{ {
if (add_prefix) if (add_prefix)
{ {
@@ -1363,7 +1340,7 @@ class binary_writer
} }
write_number(static_cast<std::uint8_t>(n)); write_number(static_cast<std::uint8_t>(n));
} }
else if ((std::numeric_limits<std::int16_t>::min)() <= n and n <= (std::numeric_limits<std::int16_t>::max)()) else if ((std::numeric_limits<std::int16_t>::min)() <= n && n <= (std::numeric_limits<std::int16_t>::max)())
{ {
if (add_prefix) if (add_prefix)
{ {
@@ -1371,7 +1348,7 @@ class binary_writer
} }
write_number(static_cast<std::int16_t>(n)); write_number(static_cast<std::int16_t>(n));
} }
else if ((std::numeric_limits<std::int32_t>::min)() <= n and n <= (std::numeric_limits<std::int32_t>::max)()) else if ((std::numeric_limits<std::int32_t>::min)() <= n && n <= (std::numeric_limits<std::int32_t>::max)())
{ {
if (add_prefix) if (add_prefix)
{ {
@@ -1379,7 +1356,7 @@ class binary_writer
} }
write_number(static_cast<std::int32_t>(n)); write_number(static_cast<std::int32_t>(n));
} }
else if ((std::numeric_limits<std::int64_t>::min)() <= n and n <= (std::numeric_limits<std::int64_t>::max)()) else if ((std::numeric_limits<std::int64_t>::min)() <= n && n <= (std::numeric_limits<std::int64_t>::max)())
{ {
if (add_prefix) if (add_prefix)
{ {
@@ -1416,19 +1393,19 @@ class binary_writer
case value_t::number_integer: case value_t::number_integer:
{ {
if ((std::numeric_limits<std::int8_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)()) if ((std::numeric_limits<std::int8_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)())
{ {
return 'i'; return 'i';
} }
if ((std::numeric_limits<std::uint8_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<std::uint8_t>::max)()) if ((std::numeric_limits<std::uint8_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::uint8_t>::max)())
{ {
return 'U'; return 'U';
} }
if ((std::numeric_limits<std::int16_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)()) if ((std::numeric_limits<std::int16_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)())
{ {
return 'I'; return 'I';
} }
if ((std::numeric_limits<std::int32_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)()) if ((std::numeric_limits<std::int32_t>::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)())
{ {
return 'l'; return 'l';
} }
@@ -1518,20 +1495,40 @@ class binary_writer
oa->write_characters(vec.data(), sizeof(NumberType)); oa->write_characters(vec.data(), sizeof(NumberType));
} }
void write_compact_float(const number_float_t n, detail::input_format_t format)
{
if (static_cast<double>(n) >= static_cast<double>(std::numeric_limits<float>::lowest()) &&
static_cast<double>(n) <= static_cast<double>((std::numeric_limits<float>::max)()) &&
static_cast<double>(static_cast<float>(n)) == static_cast<double>(n))
{
oa->write_character(format == detail::input_format_t::cbor
? get_cbor_float_prefix(static_cast<float>(n))
: get_msgpack_float_prefix(static_cast<float>(n)));
write_number(static_cast<float>(n));
}
else
{
oa->write_character(format == detail::input_format_t::cbor
? get_cbor_float_prefix(n)
: get_msgpack_float_prefix(n));
write_number(n);
}
}
public: public:
// The following to_char_type functions are implement the conversion // The following to_char_type functions are implement the conversion
// between uint8_t and CharType. In case CharType is not unsigned, // between uint8_t and CharType. In case CharType is not unsigned,
// such a conversion is required to allow values greater than 128. // such a conversion is required to allow values greater than 128.
// See <https://github.com/nlohmann/json/issues/1286> for a discussion. // See <https://github.com/nlohmann/json/issues/1286> for a discussion.
template < typename C = CharType, template < typename C = CharType,
enable_if_t < std::is_signed<C>::value and std::is_signed<char>::value > * = nullptr > enable_if_t < std::is_signed<C>::value && std::is_signed<char>::value > * = nullptr >
static constexpr CharType to_char_type(std::uint8_t x) noexcept static constexpr CharType to_char_type(std::uint8_t x) noexcept
{ {
return *reinterpret_cast<char*>(&x); return *reinterpret_cast<char*>(&x);
} }
template < typename C = CharType, template < typename C = CharType,
enable_if_t < std::is_signed<C>::value and std::is_unsigned<char>::value > * = nullptr > enable_if_t < std::is_signed<C>::value && std::is_unsigned<char>::value > * = nullptr >
static CharType to_char_type(std::uint8_t x) noexcept static CharType to_char_type(std::uint8_t x) noexcept
{ {
static_assert(sizeof(std::uint8_t) == sizeof(CharType), "size of CharType must be equal to std::uint8_t"); static_assert(sizeof(std::uint8_t) == sizeof(CharType), "size of CharType must be equal to std::uint8_t");
@@ -1550,8 +1547,8 @@ class binary_writer
template < typename InputCharType, typename C = CharType, template < typename InputCharType, typename C = CharType,
enable_if_t < enable_if_t <
std::is_signed<C>::value and std::is_signed<C>::value &&
std::is_signed<char>::value and std::is_signed<char>::value &&
std::is_same<char, typename std::remove_cv<InputCharType>::type>::value std::is_same<char, typename std::remove_cv<InputCharType>::type>::value
> * = nullptr > > * = nullptr >
static constexpr CharType to_char_type(InputCharType x) noexcept static constexpr CharType to_char_type(InputCharType x) noexcept
+31 -33
View File
@@ -2,18 +2,16 @@
#include <algorithm> // reverse, remove, fill, find, none_of #include <algorithm> // reverse, remove, fill, find, none_of
#include <array> // array #include <array> // array
#include <cassert> // assert
#include <clocale> // localeconv, lconv #include <clocale> // localeconv, lconv
#include <cmath> // labs, isfinite, isnan, signbit #include <cmath> // labs, isfinite, isnan, signbit
#include <cstddef> // size_t, ptrdiff_t #include <cstddef> // size_t, ptrdiff_t
#include <cstdint> // uint8_t #include <cstdint> // uint8_t
#include <cstdio> // snprintf #include <cstdio> // snprintf
#include <limits> // numeric_limits #include <limits> // numeric_limits
#include <string> // string #include <string> // string, char_traits
#include <type_traits> // is_same #include <type_traits> // is_same
#include <utility> // move #include <utility> // move
#include <nlohmann/detail/boolean_operators.hpp>
#include <nlohmann/detail/conversions/to_chars.hpp> #include <nlohmann/detail/conversions/to_chars.hpp>
#include <nlohmann/detail/exceptions.hpp> #include <nlohmann/detail/exceptions.hpp>
#include <nlohmann/detail/macro_scope.hpp> #include <nlohmann/detail/macro_scope.hpp>
@@ -59,8 +57,8 @@ class serializer
error_handler_t error_handler_ = error_handler_t::strict) error_handler_t error_handler_ = error_handler_t::strict)
: o(std::move(s)) : o(std::move(s))
, loc(std::localeconv()) , loc(std::localeconv())
, thousands_sep(loc->thousands_sep == nullptr ? '\0' : * (loc->thousands_sep)) , thousands_sep(loc->thousands_sep == nullptr ? '\0' : std::char_traits<char>::to_char_type(* (loc->thousands_sep)))
, decimal_point(loc->decimal_point == nullptr ? '\0' : * (loc->decimal_point)) , decimal_point(loc->decimal_point == nullptr ? '\0' : std::char_traits<char>::to_char_type(* (loc->decimal_point)))
, indent_char(ichar) , indent_char(ichar)
, indent_string(512, indent_char) , indent_string(512, indent_char)
, error_handler(error_handler_) , error_handler(error_handler_)
@@ -135,8 +133,8 @@ class serializer
} }
// last element // last element
assert(i != val.m_value.object->cend()); JSON_ASSERT(i != val.m_value.object->cend());
assert(std::next(i) == val.m_value.object->cend()); JSON_ASSERT(std::next(i) == val.m_value.object->cend());
o->write_characters(indent_string.c_str(), new_indent); o->write_characters(indent_string.c_str(), new_indent);
o->write_character('\"'); o->write_character('\"');
dump_escaped(i->first, ensure_ascii); dump_escaped(i->first, ensure_ascii);
@@ -163,8 +161,8 @@ class serializer
} }
// last element // last element
assert(i != val.m_value.object->cend()); JSON_ASSERT(i != val.m_value.object->cend());
assert(std::next(i) == val.m_value.object->cend()); JSON_ASSERT(std::next(i) == val.m_value.object->cend());
o->write_character('\"'); o->write_character('\"');
dump_escaped(i->first, ensure_ascii); dump_escaped(i->first, ensure_ascii);
o->write_characters("\":", 2); o->write_characters("\":", 2);
@@ -205,7 +203,7 @@ class serializer
} }
// last element // last element
assert(not val.m_value.array->empty()); JSON_ASSERT(!val.m_value.array->empty());
o->write_characters(indent_string.c_str(), new_indent); o->write_characters(indent_string.c_str(), new_indent);
dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent); dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent);
@@ -226,7 +224,7 @@ class serializer
} }
// last element // last element
assert(not val.m_value.array->empty()); JSON_ASSERT(!val.m_value.array->empty());
dump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent); dump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent);
o->write_character(']'); o->write_character(']');
@@ -260,7 +258,7 @@ class serializer
o->write_characters("\"bytes\": [", 10); o->write_characters("\"bytes\": [", 10);
if (not val.m_value.binary->empty()) if (!val.m_value.binary->empty())
{ {
for (auto i = val.m_value.binary->cbegin(); for (auto i = val.m_value.binary->cbegin();
i != val.m_value.binary->cend() - 1; ++i) i != val.m_value.binary->cend() - 1; ++i)
@@ -291,7 +289,7 @@ class serializer
{ {
o->write_characters("{\"bytes\":[", 10); o->write_characters("{\"bytes\":[", 10);
if (not val.m_value.binary->empty()) if (!val.m_value.binary->empty())
{ {
for (auto i = val.m_value.binary->cbegin(); for (auto i = val.m_value.binary->cbegin();
i != val.m_value.binary->cend() - 1; ++i) i != val.m_value.binary->cend() - 1; ++i)
@@ -360,7 +358,7 @@ class serializer
} }
default: // LCOV_EXCL_LINE default: // LCOV_EXCL_LINE
assert(false); // LCOV_EXCL_LINE JSON_ASSERT(false); // LCOV_EXCL_LINE
} }
} }
@@ -452,7 +450,7 @@ class serializer
{ {
// escape control characters (0x00..0x1F) or, if // escape control characters (0x00..0x1F) or, if
// ensure_ascii parameter is used, non-ASCII characters // ensure_ascii parameter is used, non-ASCII characters
if ((codepoint <= 0x1F) or (ensure_ascii and (codepoint >= 0x7F))) if ((codepoint <= 0x1F) || (ensure_ascii && (codepoint >= 0x7F)))
{ {
if (codepoint <= 0xFFFF) if (codepoint <= 0xFFFF)
{ {
@@ -559,14 +557,14 @@ class serializer
} }
default: // LCOV_EXCL_LINE default: // LCOV_EXCL_LINE
assert(false); // LCOV_EXCL_LINE JSON_ASSERT(false); // LCOV_EXCL_LINE
} }
break; break;
} }
default: // decode found yet incomplete multi-byte code point default: // decode found yet incomplete multi-byte code point
{ {
if (not ensure_ascii) if (!ensure_ascii)
{ {
// code point will not be escaped - copy byte to buffer // code point will not be escaped - copy byte to buffer
string_buffer[bytes++] = s[i]; string_buffer[bytes++] = s[i];
@@ -622,7 +620,7 @@ class serializer
} }
default: // LCOV_EXCL_LINE default: // LCOV_EXCL_LINE
assert(false); // LCOV_EXCL_LINE JSON_ASSERT(false); // LCOV_EXCL_LINE
} }
} }
} }
@@ -671,8 +669,8 @@ class serializer
@tparam NumberType either @a number_integer_t or @a number_unsigned_t @tparam NumberType either @a number_integer_t or @a number_unsigned_t
*/ */
template < typename NumberType, detail::enable_if_t < template < typename NumberType, detail::enable_if_t <
std::is_same<NumberType, number_unsigned_t>::value or std::is_same<NumberType, number_unsigned_t>::value ||
std::is_same<NumberType, number_integer_t>::value or std::is_same<NumberType, number_integer_t>::value ||
std::is_same<NumberType, binary_char_t>::value, std::is_same<NumberType, binary_char_t>::value,
int > = 0 > int > = 0 >
void dump_integer(NumberType x) void dump_integer(NumberType x)
@@ -703,7 +701,7 @@ class serializer
// use a pointer to fill the buffer // use a pointer to fill the buffer
auto buffer_ptr = number_buffer.begin(); auto buffer_ptr = number_buffer.begin();
const bool is_negative = std::is_same<NumberType, number_integer_t>::value and not(x >= 0); // see issue #755 const bool is_negative = std::is_same<NumberType, number_integer_t>::value && !(x >= 0); // see issue #755
number_unsigned_t abs_value; number_unsigned_t abs_value;
unsigned int n_chars; unsigned int n_chars;
@@ -723,7 +721,7 @@ class serializer
} }
// spare 1 byte for '\0' // spare 1 byte for '\0'
assert(n_chars < number_buffer.size() - 1); JSON_ASSERT(n_chars < number_buffer.size() - 1);
// jump to the end to generate the string from backward // jump to the end to generate the string from backward
// so we later avoid reversing the result // so we later avoid reversing the result
@@ -764,7 +762,7 @@ class serializer
void dump_float(number_float_t x) void dump_float(number_float_t x)
{ {
// NaN / inf // NaN / inf
if (not std::isfinite(x)) if (!std::isfinite(x))
{ {
o->write_characters("null", 4); o->write_characters("null", 4);
return; return;
@@ -776,8 +774,8 @@ class serializer
// //
// NB: The test below works if <long double> == <double>. // NB: The test below works if <long double> == <double>.
static constexpr bool is_ieee_single_or_double static constexpr bool is_ieee_single_or_double
= (std::numeric_limits<number_float_t>::is_iec559 and std::numeric_limits<number_float_t>::digits == 24 and std::numeric_limits<number_float_t>::max_exponent == 128) or = (std::numeric_limits<number_float_t>::is_iec559 && std::numeric_limits<number_float_t>::digits == 24 && std::numeric_limits<number_float_t>::max_exponent == 128) ||
(std::numeric_limits<number_float_t>::is_iec559 and std::numeric_limits<number_float_t>::digits == 53 and std::numeric_limits<number_float_t>::max_exponent == 1024); (std::numeric_limits<number_float_t>::is_iec559 && std::numeric_limits<number_float_t>::digits == 53 && std::numeric_limits<number_float_t>::max_exponent == 1024);
dump_float(x, std::integral_constant<bool, is_ieee_single_or_double>()); dump_float(x, std::integral_constant<bool, is_ieee_single_or_double>());
} }
@@ -799,9 +797,9 @@ class serializer
std::ptrdiff_t len = (std::snprintf)(number_buffer.data(), number_buffer.size(), "%.*g", d, x); std::ptrdiff_t len = (std::snprintf)(number_buffer.data(), number_buffer.size(), "%.*g", d, x);
// negative value indicates an error // negative value indicates an error
assert(len > 0); JSON_ASSERT(len > 0);
// check if buffer was large enough // check if buffer was large enough
assert(static_cast<std::size_t>(len) < number_buffer.size()); JSON_ASSERT(static_cast<std::size_t>(len) < number_buffer.size());
// erase thousands separator // erase thousands separator
if (thousands_sep != '\0') if (thousands_sep != '\0')
@@ -809,12 +807,12 @@ class serializer
const auto end = std::remove(number_buffer.begin(), const auto end = std::remove(number_buffer.begin(),
number_buffer.begin() + len, thousands_sep); number_buffer.begin() + len, thousands_sep);
std::fill(end, number_buffer.end(), '\0'); std::fill(end, number_buffer.end(), '\0');
assert((end - number_buffer.begin()) <= len); JSON_ASSERT((end - number_buffer.begin()) <= len);
len = (end - number_buffer.begin()); len = (end - number_buffer.begin());
} }
// convert decimal point to '.' // convert decimal point to '.'
if (decimal_point != '\0' and decimal_point != '.') if (decimal_point != '\0' && decimal_point != '.')
{ {
const auto dec_pos = std::find(number_buffer.begin(), number_buffer.end(), decimal_point); const auto dec_pos = std::find(number_buffer.begin(), number_buffer.end(), decimal_point);
if (dec_pos != number_buffer.end()) if (dec_pos != number_buffer.end())
@@ -830,7 +828,7 @@ class serializer
std::none_of(number_buffer.begin(), number_buffer.begin() + len + 1, std::none_of(number_buffer.begin(), number_buffer.begin() + len + 1,
[](char c) [](char c)
{ {
return c == '.' or c == 'e'; return c == '.' || c == 'e';
}); });
if (value_is_int_like) if (value_is_int_like)
@@ -889,7 +887,7 @@ class serializer
: (0xFFu >> type) & (byte); : (0xFFu >> type) & (byte);
std::size_t index = 256u + static_cast<size_t>(state) * 16u + static_cast<size_t>(type); std::size_t index = 256u + static_cast<size_t>(state) * 16u + static_cast<size_t>(type);
assert(index < 400); JSON_ASSERT(index < 400);
state = utf8d[index]; state = utf8d[index];
return state; return state;
} }
@@ -901,7 +899,7 @@ class serializer
*/ */
number_unsigned_t remove_sign(number_unsigned_t x) number_unsigned_t remove_sign(number_unsigned_t x)
{ {
assert(false); // LCOV_EXCL_LINE JSON_ASSERT(false); // LCOV_EXCL_LINE
return x; // LCOV_EXCL_LINE return x; // LCOV_EXCL_LINE
} }
@@ -916,7 +914,7 @@ class serializer
*/ */
inline number_unsigned_t remove_sign(number_integer_t x) noexcept inline number_unsigned_t remove_sign(number_integer_t x) noexcept
{ {
assert(x < 0 and x < (std::numeric_limits<number_integer_t>::max)()); JSON_ASSERT(x < 0 && x < (std::numeric_limits<number_integer_t>::max)());
return static_cast<number_unsigned_t>(-(x + 1)) + 1; return static_cast<number_unsigned_t>(-(x + 1)) + 1;
} }
+1 -3
View File
@@ -5,8 +5,6 @@
#include <cstdint> // uint8_t #include <cstdint> // uint8_t
#include <string> // string #include <string> // string
#include <nlohmann/detail/boolean_operators.hpp>
namespace nlohmann namespace nlohmann
{ {
namespace detail namespace detail
@@ -77,7 +75,7 @@ inline bool operator<(const value_t lhs, const value_t rhs) noexcept
const auto l_index = static_cast<std::size_t>(lhs); const auto l_index = static_cast<std::size_t>(lhs);
const auto r_index = static_cast<std::size_t>(rhs); const auto r_index = static_cast<std::size_t>(rhs);
return l_index < order.size() and r_index < order.size() and order[l_index] < order[r_index]; return l_index < order.size() && r_index < order.size() && order[l_index] < order[r_index];
} }
} // namespace detail } // namespace detail
} // namespace nlohmann } // namespace nlohmann
+195 -128
View File
@@ -35,7 +35,6 @@ SOFTWARE.
#define NLOHMANN_JSON_VERSION_PATCH 0 #define NLOHMANN_JSON_VERSION_PATCH 0
#include <algorithm> // all_of, find, for_each #include <algorithm> // all_of, find, for_each
#include <cassert> // assert
#include <cstddef> // nullptr_t, ptrdiff_t, size_t #include <cstddef> // nullptr_t, ptrdiff_t, size_t
#include <functional> // hash, less #include <functional> // hash, less
#include <initializer_list> // initializer_list #include <initializer_list> // initializer_list
@@ -49,7 +48,6 @@ SOFTWARE.
#include <nlohmann/adl_serializer.hpp> #include <nlohmann/adl_serializer.hpp>
#include <nlohmann/byte_container_with_subtype.hpp> #include <nlohmann/byte_container_with_subtype.hpp>
#include <nlohmann/detail/boolean_operators.hpp>
#include <nlohmann/detail/conversions/from_json.hpp> #include <nlohmann/detail/conversions/from_json.hpp>
#include <nlohmann/detail/conversions/to_json.hpp> #include <nlohmann/detail/conversions/to_json.hpp>
#include <nlohmann/detail/exceptions.hpp> #include <nlohmann/detail/exceptions.hpp>
@@ -72,6 +70,7 @@ SOFTWARE.
#include <nlohmann/detail/output/serializer.hpp> #include <nlohmann/detail/output/serializer.hpp>
#include <nlohmann/detail/value_t.hpp> #include <nlohmann/detail/value_t.hpp>
#include <nlohmann/json_fwd.hpp> #include <nlohmann/json_fwd.hpp>
#include <nlohmann/ordered_map.hpp>
/*! /*!
@brief namespace for Niels Lohmann @brief namespace for Niels Lohmann
@@ -196,10 +195,12 @@ class basic_json
static ::nlohmann::detail::parser<basic_json, InputAdapterType> parser( static ::nlohmann::detail::parser<basic_json, InputAdapterType> parser(
InputAdapterType adapter, InputAdapterType adapter,
detail::parser_callback_t<basic_json>cb = nullptr, detail::parser_callback_t<basic_json>cb = nullptr,
bool allow_exceptions = true const bool allow_exceptions = true,
const bool ignore_comments = false
) )
{ {
return ::nlohmann::detail::parser<basic_json, InputAdapterType>(std::move(adapter), std::move(cb), allow_exceptions); return ::nlohmann::detail::parser<basic_json, InputAdapterType>(std::move(adapter),
std::move(cb), allow_exceptions, ignore_comments);
} }
using primitive_iterator_t = ::nlohmann::detail::primitive_iterator_t; using primitive_iterator_t = ::nlohmann::detail::primitive_iterator_t;
@@ -922,7 +923,7 @@ class basic_json
}; };
std::unique_ptr<T, decltype(deleter)> object(AllocatorTraits::allocate(alloc, 1), deleter); std::unique_ptr<T, decltype(deleter)> object(AllocatorTraits::allocate(alloc, 1), deleter);
AllocatorTraits::construct(alloc, object.get(), std::forward<Args>(args)...); AllocatorTraits::construct(alloc, object.get(), std::forward<Args>(args)...);
assert(object != nullptr); JSON_ASSERT(object != nullptr);
return object.release(); return object.release();
} }
@@ -1135,7 +1136,7 @@ class basic_json
} }
} }
while (not stack.empty()) while (!stack.empty())
{ {
// move the last item to local variable to be processed // move the last item to local variable to be processed
basic_json current_item(std::move(stack.back())); basic_json current_item(std::move(stack.back()));
@@ -1217,10 +1218,10 @@ class basic_json
*/ */
void assert_invariant() const noexcept void assert_invariant() const noexcept
{ {
assert(m_type != value_t::object or m_value.object != nullptr); JSON_ASSERT(m_type != value_t::object || m_value.object != nullptr);
assert(m_type != value_t::array or m_value.array != nullptr); JSON_ASSERT(m_type != value_t::array || m_value.array != nullptr);
assert(m_type != value_t::string or m_value.string != nullptr); JSON_ASSERT(m_type != value_t::string || m_value.string != nullptr);
assert(m_type != value_t::binary or m_value.binary != nullptr); JSON_ASSERT(m_type != value_t::binary || m_value.binary != nullptr);
} }
public: public:
@@ -1431,7 +1432,7 @@ class basic_json
template < typename CompatibleType, template < typename CompatibleType,
typename U = detail::uncvref_t<CompatibleType>, typename U = detail::uncvref_t<CompatibleType>,
detail::enable_if_t < detail::enable_if_t <
not detail::is_basic_json<U>::value and detail::is_compatible_type<basic_json_t, U>::value, int> = 0> !detail::is_basic_json<U>::value && detail::is_compatible_type<basic_json_t, U>::value, int > = 0 >
basic_json(CompatibleType && val) noexcept(noexcept( basic_json(CompatibleType && val) noexcept(noexcept(
JSONSerializer<U>::to_json(std::declval<basic_json_t&>(), JSONSerializer<U>::to_json(std::declval<basic_json_t&>(),
std::forward<CompatibleType>(val)))) std::forward<CompatibleType>(val))))
@@ -1468,7 +1469,7 @@ class basic_json
*/ */
template < typename BasicJsonType, template < typename BasicJsonType,
detail::enable_if_t < detail::enable_if_t <
detail::is_basic_json<BasicJsonType>::value and not std::is_same<basic_json, BasicJsonType>::value, int> = 0> detail::is_basic_json<BasicJsonType>::value&& !std::is_same<basic_json, BasicJsonType>::value, int > = 0 >
basic_json(const BasicJsonType& val) basic_json(const BasicJsonType& val)
{ {
using other_boolean_t = typename BasicJsonType::boolean_t; using other_boolean_t = typename BasicJsonType::boolean_t;
@@ -1513,7 +1514,7 @@ class basic_json
m_type = value_t::discarded; m_type = value_t::discarded;
break; break;
default: // LCOV_EXCL_LINE default: // LCOV_EXCL_LINE
assert(false); // LCOV_EXCL_LINE JSON_ASSERT(false); // LCOV_EXCL_LINE
} }
assert_invariant(); assert_invariant();
} }
@@ -1601,11 +1602,11 @@ class basic_json
bool is_an_object = std::all_of(init.begin(), init.end(), bool is_an_object = std::all_of(init.begin(), init.end(),
[](const detail::json_ref<basic_json>& element_ref) [](const detail::json_ref<basic_json>& element_ref)
{ {
return element_ref->is_array() and element_ref->size() == 2 and (*element_ref)[0].is_string(); return element_ref->is_array() && element_ref->size() == 2 && (*element_ref)[0].is_string();
}); });
// adjust type if type deduction is not wanted // adjust type if type deduction is not wanted
if (not type_deduction) if (!type_deduction)
{ {
// if array is wanted, do not create an object though possible // if array is wanted, do not create an object though possible
if (manual_type == value_t::array) if (manual_type == value_t::array)
@@ -1614,7 +1615,7 @@ class basic_json
} }
// if object is wanted but impossible, throw an exception // if object is wanted but impossible, throw an exception
if (JSON_HEDLEY_UNLIKELY(manual_type == value_t::object and not is_an_object)) if (JSON_HEDLEY_UNLIKELY(manual_type == value_t::object && !is_an_object))
{ {
JSON_THROW(type_error::create(301, "cannot create object from initializer list")); JSON_THROW(type_error::create(301, "cannot create object from initializer list"));
} }
@@ -1909,12 +1910,12 @@ class basic_json
@since version 1.0.0 @since version 1.0.0
*/ */
template < class InputIT, typename std::enable_if < template < class InputIT, typename std::enable_if <
std::is_same<InputIT, typename basic_json_t::iterator>::value or std::is_same<InputIT, typename basic_json_t::iterator>::value ||
std::is_same<InputIT, typename basic_json_t::const_iterator>::value, int >::type = 0 > std::is_same<InputIT, typename basic_json_t::const_iterator>::value, int >::type = 0 >
basic_json(InputIT first, InputIT last) basic_json(InputIT first, InputIT last)
{ {
assert(first.m_object != nullptr); JSON_ASSERT(first.m_object != nullptr);
assert(last.m_object != nullptr); JSON_ASSERT(last.m_object != nullptr);
// make sure iterator fits the current value // make sure iterator fits the current value
if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object)) if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
@@ -1934,8 +1935,8 @@ class basic_json
case value_t::number_unsigned: case value_t::number_unsigned:
case value_t::string: case value_t::string:
{ {
if (JSON_HEDLEY_UNLIKELY(not first.m_it.primitive_iterator.is_begin() if (JSON_HEDLEY_UNLIKELY(!first.m_it.primitive_iterator.is_begin()
or not last.m_it.primitive_iterator.is_end())) || !last.m_it.primitive_iterator.is_end()))
{ {
JSON_THROW(invalid_iterator::create(204, "iterators out of range")); JSON_THROW(invalid_iterator::create(204, "iterators out of range"));
} }
@@ -2168,9 +2169,9 @@ class basic_json
@since version 1.0.0 @since version 1.0.0
*/ */
basic_json& operator=(basic_json other) noexcept ( basic_json& operator=(basic_json other) noexcept (
std::is_nothrow_move_constructible<value_t>::value and std::is_nothrow_move_constructible<value_t>::value&&
std::is_nothrow_move_assignable<value_t>::value and std::is_nothrow_move_assignable<value_t>::value&&
std::is_nothrow_move_constructible<json_value>::value and std::is_nothrow_move_constructible<json_value>::value&&
std::is_nothrow_move_assignable<json_value>::value std::is_nothrow_move_assignable<json_value>::value
) )
{ {
@@ -2236,7 +2237,8 @@ class basic_json
@param[in] error_handler how to react on decoding errors; there are three @param[in] error_handler how to react on decoding errors; there are three
possible values: `strict` (throws and exception in case a decoding error possible values: `strict` (throws and exception in case a decoding error
occurs; default), `replace` (replace invalid UTF-8 sequences with U+FFFD), occurs; default), `replace` (replace invalid UTF-8 sequences with U+FFFD),
and `ignore` (ignore invalid UTF-8 sequences during serialization). and `ignore` (ignore invalid UTF-8 sequences during serialization; all
bytes are copied to the output unchanged).
@return string containing the serialization of the JSON value @return string containing the serialization of the JSON value
@@ -2349,7 +2351,7 @@ class basic_json
*/ */
constexpr bool is_primitive() const noexcept constexpr bool is_primitive() const noexcept
{ {
return is_null() or is_string() or is_boolean() or is_number() or is_binary(); return is_null() || is_string() || is_boolean() || is_number() || is_binary();
} }
/*! /*!
@@ -2376,7 +2378,7 @@ class basic_json
*/ */
constexpr bool is_structured() const noexcept constexpr bool is_structured() const noexcept
{ {
return is_array() or is_object(); return is_array() || is_object();
} }
/*! /*!
@@ -2450,7 +2452,7 @@ class basic_json
*/ */
constexpr bool is_number() const noexcept constexpr bool is_number() const noexcept
{ {
return is_number_integer() or is_number_float(); return is_number_integer() || is_number_float();
} }
/*! /*!
@@ -2479,7 +2481,7 @@ class basic_json
*/ */
constexpr bool is_number_integer() const noexcept constexpr bool is_number_integer() const noexcept
{ {
return m_type == value_t::number_integer or m_type == value_t::number_unsigned; return m_type == value_t::number_integer || m_type == value_t::number_unsigned;
} }
/*! /*!
@@ -2861,7 +2863,7 @@ class basic_json
@since version 3.2.0 @since version 3.2.0
*/ */
template < typename BasicJsonType, detail::enable_if_t < template < typename BasicJsonType, detail::enable_if_t <
not std::is_same<BasicJsonType, basic_json>::value and !std::is_same<BasicJsonType, basic_json>::value&&
detail::is_basic_json<BasicJsonType>::value, int > = 0 > detail::is_basic_json<BasicJsonType>::value, int > = 0 >
BasicJsonType get() const BasicJsonType get() const
{ {
@@ -2909,9 +2911,9 @@ class basic_json
*/ */
template < typename ValueTypeCV, typename ValueType = detail::uncvref_t<ValueTypeCV>, template < typename ValueTypeCV, typename ValueType = detail::uncvref_t<ValueTypeCV>,
detail::enable_if_t < detail::enable_if_t <
not detail::is_basic_json<ValueType>::value and !detail::is_basic_json<ValueType>::value &&
detail::has_from_json<basic_json_t, ValueType>::value and detail::has_from_json<basic_json_t, ValueType>::value &&
not detail::has_non_default_from_json<basic_json_t, ValueType>::value, !detail::has_non_default_from_json<basic_json_t, ValueType>::value,
int > = 0 > int > = 0 >
ValueType get() const noexcept(noexcept( ValueType get() const noexcept(noexcept(
JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>(), std::declval<ValueType&>()))) JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>(), std::declval<ValueType&>())))
@@ -2919,7 +2921,7 @@ class basic_json
// we cannot static_assert on ValueTypeCV being non-const, because // we cannot static_assert on ValueTypeCV being non-const, because
// there is support for get<const basic_json_t>(), which is why we // there is support for get<const basic_json_t>(), which is why we
// still need the uncvref // still need the uncvref
static_assert(not std::is_reference<ValueTypeCV>::value, static_assert(!std::is_reference<ValueTypeCV>::value,
"get() cannot be used with reference types, you might want to use get_ref()"); "get() cannot be used with reference types, you might want to use get_ref()");
static_assert(std::is_default_constructible<ValueType>::value, static_assert(std::is_default_constructible<ValueType>::value,
"types must be DefaultConstructible when used with get()"); "types must be DefaultConstructible when used with get()");
@@ -2961,13 +2963,13 @@ class basic_json
@since version 2.1.0 @since version 2.1.0
*/ */
template < typename ValueTypeCV, typename ValueType = detail::uncvref_t<ValueTypeCV>, template < typename ValueTypeCV, typename ValueType = detail::uncvref_t<ValueTypeCV>,
detail::enable_if_t<not std::is_same<basic_json_t, ValueType>::value and detail::enable_if_t < !std::is_same<basic_json_t, ValueType>::value &&
detail::has_non_default_from_json<basic_json_t, ValueType>::value, detail::has_non_default_from_json<basic_json_t, ValueType>::value,
int > = 0 > int > = 0 >
ValueType get() const noexcept(noexcept( ValueType get() const noexcept(noexcept(
JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>()))) JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>())))
{ {
static_assert(not std::is_reference<ValueTypeCV>::value, static_assert(!std::is_reference<ValueTypeCV>::value,
"get() cannot be used with reference types, you might want to use get_ref()"); "get() cannot be used with reference types, you might want to use get_ref()");
return JSONSerializer<ValueType>::from_json(*this); return JSONSerializer<ValueType>::from_json(*this);
} }
@@ -3007,7 +3009,7 @@ class basic_json
*/ */
template < typename ValueType, template < typename ValueType,
detail::enable_if_t < detail::enable_if_t <
not detail::is_basic_json<ValueType>::value and !detail::is_basic_json<ValueType>::value&&
detail::has_from_json<basic_json_t, ValueType>::value, detail::has_from_json<basic_json_t, ValueType>::value,
int > = 0 > int > = 0 >
ValueType & get_to(ValueType& v) const noexcept(noexcept( ValueType & get_to(ValueType& v) const noexcept(noexcept(
@@ -3017,6 +3019,18 @@ class basic_json
return v; return v;
} }
// specialization to allow to call get_to with a basic_json value
// see https://github.com/nlohmann/json/issues/2175
template<typename ValueType,
detail::enable_if_t <
detail::is_basic_json<ValueType>::value,
int> = 0>
ValueType & get_to(ValueType& v) const
{
v = *this;
return v;
}
template < template <
typename T, std::size_t N, typename T, std::size_t N,
typename Array = T (&)[N], typename Array = T (&)[N],
@@ -3070,7 +3084,7 @@ class basic_json
@copydoc get_ptr() @copydoc get_ptr()
*/ */
template < typename PointerType, typename std::enable_if < template < typename PointerType, typename std::enable_if <
std::is_pointer<PointerType>::value and std::is_pointer<PointerType>::value&&
std::is_const<typename std::remove_pointer<PointerType>::type>::value, int >::type = 0 > std::is_const<typename std::remove_pointer<PointerType>::type>::value, int >::type = 0 >
constexpr auto get_ptr() const noexcept -> decltype(std::declval<const basic_json_t&>().get_impl_ptr(std::declval<PointerType>())) constexpr auto get_ptr() const noexcept -> decltype(std::declval<const basic_json_t&>().get_impl_ptr(std::declval<PointerType>()))
{ {
@@ -3164,7 +3178,7 @@ class basic_json
@copydoc get_ref() @copydoc get_ref()
*/ */
template < typename ReferenceType, typename std::enable_if < template < typename ReferenceType, typename std::enable_if <
std::is_reference<ReferenceType>::value and std::is_reference<ReferenceType>::value&&
std::is_const<typename std::remove_reference<ReferenceType>::type>::value, int >::type = 0 > std::is_const<typename std::remove_reference<ReferenceType>::type>::value, int >::type = 0 >
ReferenceType get_ref() const ReferenceType get_ref() const
{ {
@@ -3202,15 +3216,15 @@ class basic_json
@since version 1.0.0 @since version 1.0.0
*/ */
template < typename ValueType, typename std::enable_if < template < typename ValueType, typename std::enable_if <
not std::is_pointer<ValueType>::value and !std::is_pointer<ValueType>::value&&
not std::is_same<ValueType, detail::json_ref<basic_json>>::value and !std::is_same<ValueType, detail::json_ref<basic_json>>::value&&
not std::is_same<ValueType, typename string_t::value_type>::value and !std::is_same<ValueType, typename string_t::value_type>::value&&
not detail::is_basic_json<ValueType>::value !detail::is_basic_json<ValueType>::value
and not std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value && !std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value
#if defined(JSON_HAS_CPP_17) && (defined(__GNUC__) || (defined(_MSC_VER) and _MSC_VER >= 1910 and _MSC_VER <= 1914)) #if defined(JSON_HAS_CPP_17) && (defined(__GNUC__) || (defined(_MSC_VER) && _MSC_VER >= 1910 && _MSC_VER <= 1914))
and not std::is_same<ValueType, typename std::string_view>::value && !std::is_same<ValueType, typename std::string_view>::value
#endif #endif
and detail::is_detected<detail::get_template_function, const basic_json_t&, ValueType>::value && detail::is_detected<detail::get_template_function, const basic_json_t&, ValueType>::value
, int >::type = 0 > , int >::type = 0 >
operator ValueType() const operator ValueType() const
{ {
@@ -3229,7 +3243,7 @@ class basic_json
*/ */
binary_t& get_binary() binary_t& get_binary()
{ {
if (not is_binary()) if (!is_binary())
{ {
JSON_THROW(type_error::create(302, "type must be binary, but is " + std::string(type_name()))); JSON_THROW(type_error::create(302, "type must be binary, but is " + std::string(type_name())));
} }
@@ -3240,7 +3254,7 @@ class basic_json
/// @copydoc get_binary() /// @copydoc get_binary()
const binary_t& get_binary() const const binary_t& get_binary() const
{ {
if (not is_binary()) if (!is_binary())
{ {
JSON_THROW(type_error::create(302, "type must be binary, but is " + std::string(type_name()))); JSON_THROW(type_error::create(302, "type must be binary, but is " + std::string(type_name())));
} }
@@ -3618,7 +3632,7 @@ class basic_json
// const operator[] only works for objects // const operator[] only works for objects
if (JSON_HEDLEY_LIKELY(is_object())) if (JSON_HEDLEY_LIKELY(is_object()))
{ {
assert(m_value.object->find(key) != m_value.object->end()); JSON_ASSERT(m_value.object->find(key) != m_value.object->end());
return m_value.object->find(key)->second; return m_value.object->find(key)->second;
} }
@@ -3710,7 +3724,7 @@ class basic_json
// at only works for objects // at only works for objects
if (JSON_HEDLEY_LIKELY(is_object())) if (JSON_HEDLEY_LIKELY(is_object()))
{ {
assert(m_value.object->find(key) != m_value.object->end()); JSON_ASSERT(m_value.object->find(key) != m_value.object->end());
return m_value.object->find(key)->second; return m_value.object->find(key)->second;
} }
@@ -3769,7 +3783,7 @@ class basic_json
*/ */
template < class ValueType, typename std::enable_if < template < class ValueType, typename std::enable_if <
std::is_convertible<basic_json_t, ValueType>::value std::is_convertible<basic_json_t, ValueType>::value
and not std::is_same<value_t, ValueType>::value, int>::type = 0> && !std::is_same<value_t, ValueType>::value, int >::type = 0 >
ValueType value(const typename object_t::key_type& key, const ValueType& default_value) const ValueType value(const typename object_t::key_type& key, const ValueType& default_value) const
{ {
// at only works for objects // at only works for objects
@@ -4004,7 +4018,7 @@ class basic_json
@since version 1.0.0 @since version 1.0.0
*/ */
template < class IteratorType, typename std::enable_if < template < class IteratorType, typename std::enable_if <
std::is_same<IteratorType, typename basic_json_t::iterator>::value or std::is_same<IteratorType, typename basic_json_t::iterator>::value ||
std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int >::type std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int >::type
= 0 > = 0 >
IteratorType erase(IteratorType pos) IteratorType erase(IteratorType pos)
@@ -4026,7 +4040,7 @@ class basic_json
case value_t::string: case value_t::string:
case value_t::binary: case value_t::binary:
{ {
if (JSON_HEDLEY_UNLIKELY(not pos.m_it.primitive_iterator.is_begin())) if (JSON_HEDLEY_UNLIKELY(!pos.m_it.primitive_iterator.is_begin()))
{ {
JSON_THROW(invalid_iterator::create(205, "iterator out of range")); JSON_THROW(invalid_iterator::create(205, "iterator out of range"));
} }
@@ -4117,13 +4131,13 @@ class basic_json
@since version 1.0.0 @since version 1.0.0
*/ */
template < class IteratorType, typename std::enable_if < template < class IteratorType, typename std::enable_if <
std::is_same<IteratorType, typename basic_json_t::iterator>::value or std::is_same<IteratorType, typename basic_json_t::iterator>::value ||
std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int >::type std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int >::type
= 0 > = 0 >
IteratorType erase(IteratorType first, IteratorType last) IteratorType erase(IteratorType first, IteratorType last)
{ {
// make sure iterator fits the current value // make sure iterator fits the current value
if (JSON_HEDLEY_UNLIKELY(this != first.m_object or this != last.m_object)) if (JSON_HEDLEY_UNLIKELY(this != first.m_object || this != last.m_object))
{ {
JSON_THROW(invalid_iterator::create(203, "iterators do not fit current value")); JSON_THROW(invalid_iterator::create(203, "iterators do not fit current value"));
} }
@@ -4139,8 +4153,8 @@ class basic_json
case value_t::string: case value_t::string:
case value_t::binary: case value_t::binary:
{ {
if (JSON_HEDLEY_LIKELY(not first.m_it.primitive_iterator.is_begin() if (JSON_HEDLEY_LIKELY(!first.m_it.primitive_iterator.is_begin()
or not last.m_it.primitive_iterator.is_end())) || !last.m_it.primitive_iterator.is_end()))
{ {
JSON_THROW(invalid_iterator::create(204, "iterators out of range")); JSON_THROW(invalid_iterator::create(204, "iterators out of range"));
} }
@@ -4386,10 +4400,10 @@ class basic_json
@since version 3.6.0 @since version 3.6.0
*/ */
template < typename KeyT, typename std::enable_if < template < typename KeyT, typename std::enable_if <
not std::is_same<typename std::decay<KeyT>::type, json_pointer>::value, int>::type = 0> !std::is_same<typename std::decay<KeyT>::type, json_pointer>::value, int >::type = 0 >
bool contains(KeyT && key) const bool contains(KeyT && key) const
{ {
return is_object() and m_value.object->find(std::forward<KeyT>(key)) != m_value.object->end(); return is_object() && m_value.object->find(std::forward<KeyT>(key)) != m_value.object->end();
} }
/*! /*!
@@ -5207,7 +5221,7 @@ class basic_json
void push_back(basic_json&& val) void push_back(basic_json&& val)
{ {
// push_back only works for null objects or arrays // push_back only works for null objects or arrays
if (JSON_HEDLEY_UNLIKELY(not(is_null() or is_array()))) if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))
{ {
JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name()))); JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name())));
} }
@@ -5242,7 +5256,7 @@ class basic_json
void push_back(const basic_json& val) void push_back(const basic_json& val)
{ {
// push_back only works for null objects or arrays // push_back only works for null objects or arrays
if (JSON_HEDLEY_UNLIKELY(not(is_null() or is_array()))) if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))
{ {
JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name()))); JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name())));
} }
@@ -5292,7 +5306,7 @@ class basic_json
void push_back(const typename object_t::value_type& val) void push_back(const typename object_t::value_type& val)
{ {
// push_back only works for null objects or objects // push_back only works for null objects or objects
if (JSON_HEDLEY_UNLIKELY(not(is_null() or is_object()))) if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object())))
{ {
JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name()))); JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name())));
} }
@@ -5346,7 +5360,7 @@ class basic_json
*/ */
void push_back(initializer_list_t init) void push_back(initializer_list_t init)
{ {
if (is_object() and init.size() == 2 and (*init.begin())->is_string()) if (is_object() && init.size() == 2 && (*init.begin())->is_string())
{ {
basic_json&& key = init.begin()->moved_or_copied(); basic_json&& key = init.begin()->moved_or_copied();
push_back(typename object_t::value_type( push_back(typename object_t::value_type(
@@ -5395,7 +5409,7 @@ class basic_json
reference emplace_back(Args&& ... args) reference emplace_back(Args&& ... args)
{ {
// emplace_back only works for null objects or arrays // emplace_back only works for null objects or arrays
if (JSON_HEDLEY_UNLIKELY(not(is_null() or is_array()))) if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))
{ {
JSON_THROW(type_error::create(311, "cannot use emplace_back() with " + std::string(type_name()))); JSON_THROW(type_error::create(311, "cannot use emplace_back() with " + std::string(type_name())));
} }
@@ -5448,7 +5462,7 @@ class basic_json
std::pair<iterator, bool> emplace(Args&& ... args) std::pair<iterator, bool> emplace(Args&& ... args)
{ {
// emplace only works for null objects or arrays // emplace only works for null objects or arrays
if (JSON_HEDLEY_UNLIKELY(not(is_null() or is_object()))) if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object())))
{ {
JSON_THROW(type_error::create(311, "cannot use emplace() with " + std::string(type_name()))); JSON_THROW(type_error::create(311, "cannot use emplace() with " + std::string(type_name())));
} }
@@ -5478,7 +5492,7 @@ class basic_json
iterator insert_iterator(const_iterator pos, Args&& ... args) iterator insert_iterator(const_iterator pos, Args&& ... args)
{ {
iterator result(this); iterator result(this);
assert(m_value.array != nullptr); JSON_ASSERT(m_value.array != nullptr);
auto insert_pos = std::distance(m_value.array->begin(), pos.m_it.array_iterator); auto insert_pos = std::distance(m_value.array->begin(), pos.m_it.array_iterator);
m_value.array->insert(pos.m_it.array_iterator, std::forward<Args>(args)...); m_value.array->insert(pos.m_it.array_iterator, std::forward<Args>(args)...);
@@ -5615,7 +5629,7 @@ class basic_json
iterator insert(const_iterator pos, const_iterator first, const_iterator last) iterator insert(const_iterator pos, const_iterator first, const_iterator last)
{ {
// insert only works for arrays // insert only works for arrays
if (JSON_HEDLEY_UNLIKELY(not is_array())) if (JSON_HEDLEY_UNLIKELY(!is_array()))
{ {
JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name())));
} }
@@ -5668,7 +5682,7 @@ class basic_json
iterator insert(const_iterator pos, initializer_list_t ilist) iterator insert(const_iterator pos, initializer_list_t ilist)
{ {
// insert only works for arrays // insert only works for arrays
if (JSON_HEDLEY_UNLIKELY(not is_array())) if (JSON_HEDLEY_UNLIKELY(!is_array()))
{ {
JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name())));
} }
@@ -5709,7 +5723,7 @@ class basic_json
void insert(const_iterator first, const_iterator last) void insert(const_iterator first, const_iterator last)
{ {
// insert only works for objects // insert only works for objects
if (JSON_HEDLEY_UNLIKELY(not is_object())) if (JSON_HEDLEY_UNLIKELY(!is_object()))
{ {
JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name())));
} }
@@ -5721,7 +5735,7 @@ class basic_json
} }
// passed iterators must belong to objects // passed iterators must belong to objects
if (JSON_HEDLEY_UNLIKELY(not first.m_object->is_object())) if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object()))
{ {
JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects")); JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects"));
} }
@@ -5758,11 +5772,11 @@ class basic_json
assert_invariant(); assert_invariant();
} }
if (JSON_HEDLEY_UNLIKELY(not is_object())) if (JSON_HEDLEY_UNLIKELY(!is_object()))
{ {
JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(type_name()))); JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(type_name())));
} }
if (JSON_HEDLEY_UNLIKELY(not j.is_object())) if (JSON_HEDLEY_UNLIKELY(!j.is_object()))
{ {
JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(j.type_name()))); JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(j.type_name())));
} }
@@ -5809,7 +5823,7 @@ class basic_json
assert_invariant(); assert_invariant();
} }
if (JSON_HEDLEY_UNLIKELY(not is_object())) if (JSON_HEDLEY_UNLIKELY(!is_object()))
{ {
JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(type_name()))); JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(type_name())));
} }
@@ -5821,8 +5835,8 @@ class basic_json
} }
// passed iterators must belong to objects // passed iterators must belong to objects
if (JSON_HEDLEY_UNLIKELY(not first.m_object->is_object() if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object()
or not last.m_object->is_object())) || !last.m_object->is_object()))
{ {
JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects")); JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects"));
} }
@@ -5851,9 +5865,9 @@ class basic_json
@since version 1.0.0 @since version 1.0.0
*/ */
void swap(reference other) noexcept ( void swap(reference other) noexcept (
std::is_nothrow_move_constructible<value_t>::value and std::is_nothrow_move_constructible<value_t>::value&&
std::is_nothrow_move_assignable<value_t>::value and std::is_nothrow_move_assignable<value_t>::value&&
std::is_nothrow_move_constructible<json_value>::value and std::is_nothrow_move_constructible<json_value>::value&&
std::is_nothrow_move_assignable<json_value>::value std::is_nothrow_move_assignable<json_value>::value
) )
{ {
@@ -5865,6 +5879,34 @@ class basic_json
/*! /*!
@brief exchanges the values @brief exchanges the values
Exchanges the contents of the JSON value from @a left with those of @a right. Does not
invoke any move, copy, or swap operations on individual elements. All
iterators and references remain valid. The past-the-end iterator is
invalidated. implemented as a friend function callable via ADL.
@param[in,out] left JSON value to exchange the contents with
@param[in,out] right JSON value to exchange the contents with
@complexity Constant.
@liveexample{The example below shows how JSON values can be swapped with
`swap()`.,swap__reference}
@since version 1.0.0
*/
friend void swap(reference left, reference right) noexcept (
std::is_nothrow_move_constructible<value_t>::value&&
std::is_nothrow_move_assignable<value_t>::value&&
std::is_nothrow_move_constructible<json_value>::value&&
std::is_nothrow_move_assignable<json_value>::value
)
{
left.swap(right);
}
/*!
@brief exchanges the values
Exchanges the contents of a JSON array with those of @a other. Does not Exchanges the contents of a JSON array with those of @a other. Does not
invoke any move, copy, or swap operations on individual elements. All invoke any move, copy, or swap operations on individual elements. All
iterators and references remain valid. The past-the-end iterator is iterators and references remain valid. The past-the-end iterator is
@@ -6113,27 +6155,27 @@ class basic_json
return false; return false;
} }
} }
else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_float)
{ {
return static_cast<number_float_t>(lhs.m_value.number_integer) == rhs.m_value.number_float; return static_cast<number_float_t>(lhs.m_value.number_integer) == rhs.m_value.number_float;
} }
else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer) else if (lhs_type == value_t::number_float && rhs_type == value_t::number_integer)
{ {
return lhs.m_value.number_float == static_cast<number_float_t>(rhs.m_value.number_integer); return lhs.m_value.number_float == static_cast<number_float_t>(rhs.m_value.number_integer);
} }
else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_float)
{ {
return static_cast<number_float_t>(lhs.m_value.number_unsigned) == rhs.m_value.number_float; return static_cast<number_float_t>(lhs.m_value.number_unsigned) == rhs.m_value.number_float;
} }
else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) else if (lhs_type == value_t::number_float && rhs_type == value_t::number_unsigned)
{ {
return lhs.m_value.number_float == static_cast<number_float_t>(rhs.m_value.number_unsigned); return lhs.m_value.number_float == static_cast<number_float_t>(rhs.m_value.number_unsigned);
} }
else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_integer)
{ {
return static_cast<number_integer_t>(lhs.m_value.number_unsigned) == rhs.m_value.number_integer; return static_cast<number_integer_t>(lhs.m_value.number_unsigned) == rhs.m_value.number_integer;
} }
else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_unsigned)
{ {
return lhs.m_value.number_integer == static_cast<number_integer_t>(rhs.m_value.number_unsigned); return lhs.m_value.number_integer == static_cast<number_integer_t>(rhs.m_value.number_unsigned);
} }
@@ -6183,7 +6225,7 @@ class basic_json
*/ */
friend bool operator!=(const_reference lhs, const_reference rhs) noexcept friend bool operator!=(const_reference lhs, const_reference rhs) noexcept
{ {
return not (lhs == rhs); return !(lhs == rhs);
} }
/*! /*!
@@ -6276,27 +6318,27 @@ class basic_json
return false; return false;
} }
} }
else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_float)
{ {
return static_cast<number_float_t>(lhs.m_value.number_integer) < rhs.m_value.number_float; return static_cast<number_float_t>(lhs.m_value.number_integer) < rhs.m_value.number_float;
} }
else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer) else if (lhs_type == value_t::number_float && rhs_type == value_t::number_integer)
{ {
return lhs.m_value.number_float < static_cast<number_float_t>(rhs.m_value.number_integer); return lhs.m_value.number_float < static_cast<number_float_t>(rhs.m_value.number_integer);
} }
else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_float)
{ {
return static_cast<number_float_t>(lhs.m_value.number_unsigned) < rhs.m_value.number_float; return static_cast<number_float_t>(lhs.m_value.number_unsigned) < rhs.m_value.number_float;
} }
else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) else if (lhs_type == value_t::number_float && rhs_type == value_t::number_unsigned)
{ {
return lhs.m_value.number_float < static_cast<number_float_t>(rhs.m_value.number_unsigned); return lhs.m_value.number_float < static_cast<number_float_t>(rhs.m_value.number_unsigned);
} }
else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_unsigned)
{ {
return lhs.m_value.number_integer < static_cast<number_integer_t>(rhs.m_value.number_unsigned); return lhs.m_value.number_integer < static_cast<number_integer_t>(rhs.m_value.number_unsigned);
} }
else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_integer)
{ {
return static_cast<number_integer_t>(lhs.m_value.number_unsigned) < rhs.m_value.number_integer; return static_cast<number_integer_t>(lhs.m_value.number_unsigned) < rhs.m_value.number_integer;
} }
@@ -6350,7 +6392,7 @@ class basic_json
*/ */
friend bool operator<=(const_reference lhs, const_reference rhs) noexcept friend bool operator<=(const_reference lhs, const_reference rhs) noexcept
{ {
return not (rhs < lhs); return !(rhs < lhs);
} }
/*! /*!
@@ -6396,7 +6438,7 @@ class basic_json
*/ */
friend bool operator>(const_reference lhs, const_reference rhs) noexcept friend bool operator>(const_reference lhs, const_reference rhs) noexcept
{ {
return not (lhs <= rhs); return !(lhs <= rhs);
} }
/*! /*!
@@ -6442,7 +6484,7 @@ class basic_json
*/ */
friend bool operator>=(const_reference lhs, const_reference rhs) noexcept friend bool operator>=(const_reference lhs, const_reference rhs) noexcept
{ {
return not (lhs < rhs); return !(lhs < rhs);
} }
/*! /*!
@@ -6563,6 +6605,9 @@ class basic_json
(optional) (optional)
@param[in] allow_exceptions whether to throw exceptions in case of a @param[in] allow_exceptions whether to throw exceptions in case of a
parse error (optional, true by default) parse error (optional, true by default)
@param[in] ignore_comments whether comments should be ignored and treated
like whitespace (true) or yield a parse error (true); (optional, false by
default)
@return deserialized JSON value; in case of a parse error and @return deserialized JSON value; in case of a parse error and
@a allow_exceptions set to `false`, the return value will be @a allow_exceptions set to `false`, the return value will be
@@ -6591,16 +6636,18 @@ class basic_json
@liveexample{The example below demonstrates the `parse()` function reading @liveexample{The example below demonstrates the `parse()` function reading
from a contiguous container.,parse__contiguouscontainer__parser_callback_t} from a contiguous container.,parse__contiguouscontainer__parser_callback_t}
@since version 2.0.3 (contiguous containers) @since version 2.0.3 (contiguous containers); version 3.9.0 allowed to
ignore comments.
*/ */
template<typename InputType> template<typename InputType>
JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_WARN_UNUSED_RESULT
static basic_json parse(InputType&& i, static basic_json parse(InputType&& i,
const parser_callback_t cb = nullptr, const parser_callback_t cb = nullptr,
const bool allow_exceptions = true) const bool allow_exceptions = true,
const bool ignore_comments = false)
{ {
basic_json result; basic_json result;
parser(detail::input_adapter(std::forward<InputType>(i)), cb, allow_exceptions).parse(true, result); parser(detail::input_adapter(std::forward<InputType>(i)), cb, allow_exceptions, ignore_comments).parse(true, result);
return result; return result;
} }
@@ -6617,6 +6664,9 @@ class basic_json
(optional) (optional)
@param[in] allow_exceptions whether to throw exceptions in case of a @param[in] allow_exceptions whether to throw exceptions in case of a
parse error (optional, true by default) parse error (optional, true by default)
@param[in] ignore_comments whether comments should be ignored and treated
like whitespace (true) or yield a parse error (true); (optional, false by
default)
@return deserialized JSON value; in case of a parse error and @return deserialized JSON value; in case of a parse error and
@a allow_exceptions set to `false`, the return value will be @a allow_exceptions set to `false`, the return value will be
@@ -6632,10 +6682,11 @@ class basic_json
static basic_json parse(IteratorType first, static basic_json parse(IteratorType first,
IteratorType last, IteratorType last,
const parser_callback_t cb = nullptr, const parser_callback_t cb = nullptr,
const bool allow_exceptions = true) const bool allow_exceptions = true,
const bool ignore_comments = false)
{ {
basic_json result; basic_json result;
parser(detail::input_adapter(std::move(first), std::move(last)), cb, allow_exceptions).parse(true, result); parser(detail::input_adapter(std::move(first), std::move(last)), cb, allow_exceptions, ignore_comments).parse(true, result);
return result; return result;
} }
@@ -6643,10 +6694,11 @@ class basic_json
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, parse(ptr, ptr + len)) JSON_HEDLEY_DEPRECATED_FOR(3.8.0, parse(ptr, ptr + len))
static basic_json parse(detail::span_input_adapter&& i, static basic_json parse(detail::span_input_adapter&& i,
const parser_callback_t cb = nullptr, const parser_callback_t cb = nullptr,
const bool allow_exceptions = true) const bool allow_exceptions = true,
const bool ignore_comments = false)
{ {
basic_json result; basic_json result;
parser(i.get(), cb, allow_exceptions).parse(true, result); parser(i.get(), cb, allow_exceptions, ignore_comments).parse(true, result);
return result; return result;
} }
@@ -6666,6 +6718,9 @@ class basic_json
iterators. iterators.
@param[in] i input to read from @param[in] i input to read from
@param[in] ignore_comments whether comments should be ignored and treated
like whitespace (true) or yield a parse error (true); (optional, false by
default)
@return Whether the input read from @a i is valid JSON. @return Whether the input read from @a i is valid JSON.
@@ -6678,22 +6733,25 @@ class basic_json
from a string.,accept__string} from a string.,accept__string}
*/ */
template<typename InputType> template<typename InputType>
static bool accept(InputType&& i) static bool accept(InputType&& i,
const bool ignore_comments = false)
{ {
return parser(detail::input_adapter(std::forward<InputType>(i))).accept(true); return parser(detail::input_adapter(std::forward<InputType>(i)), nullptr, false, ignore_comments).accept(true);
} }
template<typename IteratorType> template<typename IteratorType>
static bool accept(IteratorType first, IteratorType last) static bool accept(IteratorType first, IteratorType last,
const bool ignore_comments = false)
{ {
return parser(detail::input_adapter(std::move(first), std::move(last))).accept(true); return parser(detail::input_adapter(std::move(first), std::move(last)), nullptr, false, ignore_comments).accept(true);
} }
JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_WARN_UNUSED_RESULT
JSON_HEDLEY_DEPRECATED_FOR(3.8.0, accept(ptr, ptr + len)) JSON_HEDLEY_DEPRECATED_FOR(3.8.0, accept(ptr, ptr + len))
static bool accept(detail::span_input_adapter&& i) static bool accept(detail::span_input_adapter&& i,
const bool ignore_comments = false)
{ {
return parser(i.get()).accept(true); return parser(i.get(), nullptr, false, ignore_comments).accept(true);
} }
/*! /*!
@@ -6713,6 +6771,9 @@ class basic_json
@param[in,out] sax SAX event listener @param[in,out] sax SAX event listener
@param[in] format the format to parse (JSON, CBOR, MessagePack, or UBJSON) @param[in] format the format to parse (JSON, CBOR, MessagePack, or UBJSON)
@param[in] strict whether the input has to be consumed completely @param[in] strict whether the input has to be consumed completely
@param[in] ignore_comments whether comments should be ignored and treated
like whitespace (true) or yield a parse error (true); (optional, false by
default); only applies to the JSON file format.
@return return value of the last processed SAX event @return return value of the last processed SAX event
@@ -6737,11 +6798,12 @@ class basic_json
JSON_HEDLEY_NON_NULL(2) JSON_HEDLEY_NON_NULL(2)
static bool sax_parse(InputType&& i, SAX* sax, static bool sax_parse(InputType&& i, SAX* sax,
input_format_t format = input_format_t::json, input_format_t format = input_format_t::json,
const bool strict = true) const bool strict = true,
const bool ignore_comments = false)
{ {
auto ia = detail::input_adapter(std::forward<InputType>(i)); auto ia = detail::input_adapter(std::forward<InputType>(i));
return format == input_format_t::json return format == input_format_t::json
? parser(std::move(ia)).sax_parse(sax, strict) ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict)
: detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia)).sax_parse(format, sax, strict); : detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia)).sax_parse(format, sax, strict);
} }
@@ -6749,11 +6811,12 @@ class basic_json
JSON_HEDLEY_NON_NULL(3) JSON_HEDLEY_NON_NULL(3)
static bool sax_parse(IteratorType first, IteratorType last, SAX* sax, static bool sax_parse(IteratorType first, IteratorType last, SAX* sax,
input_format_t format = input_format_t::json, input_format_t format = input_format_t::json,
const bool strict = true) const bool strict = true,
const bool ignore_comments = false)
{ {
auto ia = detail::input_adapter(std::move(first), std::move(last)); auto ia = detail::input_adapter(std::move(first), std::move(last));
return format == input_format_t::json return format == input_format_t::json
? parser(std::move(ia)).sax_parse(sax, strict) ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict)
: detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia)).sax_parse(format, sax, strict); : detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia)).sax_parse(format, sax, strict);
} }
@@ -6762,11 +6825,12 @@ class basic_json
JSON_HEDLEY_NON_NULL(2) JSON_HEDLEY_NON_NULL(2)
static bool sax_parse(detail::span_input_adapter&& i, SAX* sax, static bool sax_parse(detail::span_input_adapter&& i, SAX* sax,
input_format_t format = input_format_t::json, input_format_t format = input_format_t::json,
const bool strict = true) const bool strict = true,
const bool ignore_comments = false)
{ {
auto ia = i.get(); auto ia = i.get();
return format == input_format_t::json return format == input_format_t::json
? parser(std::move(ia)).sax_parse(sax, strict) ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict)
: detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia)).sax_parse(format, sax, strict); : detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia)).sax_parse(format, sax, strict);
} }
@@ -7040,7 +7104,8 @@ class basic_json
number_unsigned | 256..65535 | uint 16 | 0xCD number_unsigned | 256..65535 | uint 16 | 0xCD
number_unsigned | 65536..4294967295 | uint 32 | 0xCE number_unsigned | 65536..4294967295 | uint 32 | 0xCE
number_unsigned | 4294967296..18446744073709551615 | uint 64 | 0xCF number_unsigned | 4294967296..18446744073709551615 | uint 64 | 0xCF
number_float | *any value* | float 64 | 0xCB number_float | *any value representable by a float* | float 32 | 0xCA
number_float | *any value NOT representable by a float* | float 64 | 0xCB
string | *length*: 0..31 | fixstr | 0xA0..0xBF string | *length*: 0..31 | fixstr | 0xA0..0xBF
string | *length*: 32..255 | str 8 | 0xD9 string | *length*: 32..255 | str 8 | 0xD9
string | *length*: 256..65535 | str 16 | 0xDA string | *length*: 256..65535 | str 16 | 0xDA
@@ -7064,9 +7129,6 @@ class basic_json
- arrays with more than 4294967295 elements - arrays with more than 4294967295 elements
- objects with more than 4294967295 elements - objects with more than 4294967295 elements
@note The following MessagePack types are not used in the conversion:
- float 32 (0xCA)
@note Any MessagePack output created @ref to_msgpack can be successfully @note Any MessagePack output created @ref to_msgpack can be successfully
parsed by @ref from_msgpack. parsed by @ref from_msgpack.
@@ -8181,7 +8243,7 @@ class basic_json
else else
{ {
const auto idx = json_pointer::array_index(last_path); const auto idx = json_pointer::array_index(last_path);
if (JSON_HEDLEY_UNLIKELY(static_cast<size_type>(idx) > parent.size())) if (JSON_HEDLEY_UNLIKELY(idx > parent.size()))
{ {
// avoid undefined behavior // avoid undefined behavior
JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range")); JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range"));
@@ -8195,7 +8257,7 @@ class basic_json
// if there exists a parent it cannot be primitive // if there exists a parent it cannot be primitive
default: // LCOV_EXCL_LINE default: // LCOV_EXCL_LINE
assert(false); // LCOV_EXCL_LINE JSON_ASSERT(false); // LCOV_EXCL_LINE
} }
}; };
@@ -8224,12 +8286,12 @@ class basic_json
else if (parent.is_array()) else if (parent.is_array())
{ {
// note erase performs range check // note erase performs range check
parent.erase(static_cast<size_type>(json_pointer::array_index(last_path))); parent.erase(json_pointer::array_index(last_path));
} }
}; };
// type check: top level value must be an array // type check: top level value must be an array
if (JSON_HEDLEY_UNLIKELY(not json_patch.is_array())) if (JSON_HEDLEY_UNLIKELY(!json_patch.is_array()))
{ {
JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects")); JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects"));
} }
@@ -8255,7 +8317,7 @@ class basic_json
} }
// check if result is of type string // check if result is of type string
if (JSON_HEDLEY_UNLIKELY(string_type and not it->second.is_string())) if (JSON_HEDLEY_UNLIKELY(string_type && !it->second.is_string()))
{ {
JSON_THROW(parse_error::create(105, 0, error_msg + " must have string member '" + member + "'")); JSON_THROW(parse_error::create(105, 0, error_msg + " must have string member '" + member + "'"));
} }
@@ -8265,7 +8327,7 @@ class basic_json
}; };
// type check: every element of the array must be an object // type check: every element of the array must be an object
if (JSON_HEDLEY_UNLIKELY(not val.is_object())) if (JSON_HEDLEY_UNLIKELY(!val.is_object()))
{ {
JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects")); JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects"));
} }
@@ -8343,7 +8405,7 @@ class basic_json
} }
// throw an exception if test fails // throw an exception if test fails
if (JSON_HEDLEY_UNLIKELY(not success)) if (JSON_HEDLEY_UNLIKELY(!success))
{ {
JSON_THROW(other_error::create(501, "unsuccessful: " + val.dump())); JSON_THROW(other_error::create(501, "unsuccessful: " + val.dump()));
} }
@@ -8425,7 +8487,7 @@ class basic_json
{ {
// first pass: traverse common elements // first pass: traverse common elements
std::size_t i = 0; std::size_t i = 0;
while (i < source.size() and i < target.size()) while (i < source.size() && i < target.size())
{ {
// recursive call to compare array values at index i // recursive call to compare array values at index i
auto temp_diff = diff(source[i], target[i], path + "/" + std::to_string(i)); auto temp_diff = diff(source[i], target[i], path + "/" + std::to_string(i));
@@ -8576,7 +8638,7 @@ class basic_json
{ {
if (apply_patch.is_object()) if (apply_patch.is_object())
{ {
if (not is_object()) if (!is_object())
{ {
*this = object(); *this = object();
} }
@@ -8659,6 +8721,9 @@ struct less<::nlohmann::detail::value_t>
} }
}; };
// C++20 prohibit function specialization in the std namespace.
#ifndef JSON_HAS_CPP_20
/*! /*!
@brief exchanges the values of two JSON objects @brief exchanges the values of two JSON objects
@@ -8666,13 +8731,15 @@ struct less<::nlohmann::detail::value_t>
*/ */
template<> template<>
inline void swap<nlohmann::json>(nlohmann::json& j1, nlohmann::json& j2) noexcept( inline void swap<nlohmann::json>(nlohmann::json& j1, nlohmann::json& j2) noexcept(
is_nothrow_move_constructible<nlohmann::json>::value and is_nothrow_move_constructible<nlohmann::json>::value&&
is_nothrow_move_assignable<nlohmann::json>::value is_nothrow_move_assignable<nlohmann::json>::value
) )
{ {
j1.swap(j2); j1.swap(j2);
} }
#endif
} // namespace std } // namespace std
/*! /*!
+13
View File
@@ -60,6 +60,19 @@ uses the standard template types.
@since version 1.0.0 @since version 1.0.0
*/ */
using json = basic_json<>; using json = basic_json<>;
template<class Key, class T, class IgnoredLess, class Allocator>
struct ordered_map;
/*!
@brief ordered JSON class
This type preserves the insertion order of object keys.
@since version 3.9.0
*/
using ordered_json = basic_json<nlohmann::ordered_map>;
} // namespace nlohmann } // namespace nlohmann
#endif // INCLUDE_NLOHMANN_JSON_FWD_HPP_ #endif // INCLUDE_NLOHMANN_JSON_FWD_HPP_
+71
View File
@@ -0,0 +1,71 @@
#pragma once
#include <functional> // less
#include <memory> // allocator
#include <utility> // pair
#include <vector> // vector
namespace nlohmann
{
/// ordered_map: a minimal map-like container that preserves insertion order
/// for use within nlohmann::basic_json<ordered_map>
template <class Key, class T, class IgnoredLess = std::less<Key>,
class Allocator = std::allocator<std::pair<const Key, T>>>
struct ordered_map : std::vector<std::pair<const Key, T>, Allocator>
{
using key_type = Key;
using mapped_type = T;
using Container = std::vector<std::pair<const Key, T>, Allocator>;
using typename Container::iterator;
using typename Container::size_type;
using typename Container::value_type;
// Explicit constructors instead of `using Container::Container`
// otherwise older compilers choke on it (GCC <= 5.5, xcode <= 9.4)
ordered_map(const Allocator& alloc = Allocator()) : Container{alloc} {}
template <class It>
ordered_map(It first, It last, const Allocator& alloc = Allocator())
: Container{first, last, alloc} {}
ordered_map(std::initializer_list<T> init, const Allocator& alloc = Allocator() )
: Container{init, alloc} {}
std::pair<iterator, bool> emplace(key_type&& key, T&& t)
{
for (auto it = this->begin(); it != this->end(); ++it)
{
if (it->first == key)
{
return {it, false};
}
}
Container::emplace_back(key, t);
return {--this->end(), true};
}
T& operator[](Key&& key)
{
return emplace(std::move(key), T{}).first->second;
}
size_type erase(const Key& key)
{
for (auto it = this->begin(); it != this->end(); ++it)
{
if (it->first == key)
{
// Since we cannot move const Keys, re-construct them in place
for (auto next = it; ++next != this->end(); ++it)
{
it->~value_type(); // Destroy but keep allocation
new (&*it) value_type{std::move(*next)};
}
Container::pop_back();
return 1;
}
}
return 0;
}
};
} // namespace nlohmann
File diff suppressed because it is too large Load Diff
+4
View File
@@ -94,7 +94,9 @@ endif()
set(files set(files
src/unit-algorithms.cpp src/unit-algorithms.cpp
src/unit-allocator.cpp src/unit-allocator.cpp
src/unit-alt-number.cpp
src/unit-alt-string.cpp src/unit-alt-string.cpp
src/unit-assert_macro.cpp
src/unit-bson.cpp src/unit-bson.cpp
src/unit-capacity.cpp src/unit-capacity.cpp
src/unit-cbor.cpp src/unit-cbor.cpp
@@ -123,6 +125,7 @@ set(files
src/unit-modifiers.cpp src/unit-modifiers.cpp
src/unit-msgpack.cpp src/unit-msgpack.cpp
src/unit-noexcept.cpp src/unit-noexcept.cpp
src/unit-ordered_json.cpp
src/unit-pointer_access.cpp src/unit-pointer_access.cpp
src/unit-readme.cpp src/unit-readme.cpp
src/unit-reference_access.cpp src/unit-reference_access.cpp
@@ -132,6 +135,7 @@ set(files
src/unit-to_chars.cpp src/unit-to_chars.cpp
src/unit-ubjson.cpp src/unit-ubjson.cpp
src/unit-udt.cpp src/unit-udt.cpp
src/unit-udt_macro.cpp
src/unit-unicode.cpp src/unit-unicode.cpp
src/unit-user_defined_input.cpp src/unit-user_defined_input.cpp
src/unit-wstring.cpp) src/unit-wstring.cpp)
+2
View File
@@ -11,8 +11,10 @@ if (${CMAKE_VERSION} VERSION_GREATER "3.11.0")
) )
set_tests_properties(cmake_fetch_content_configure PROPERTIES set_tests_properties(cmake_fetch_content_configure PROPERTIES
FIXTURES_SETUP cmake_fetch_content FIXTURES_SETUP cmake_fetch_content
LABELS git_required
) )
set_tests_properties(cmake_fetch_content_build PROPERTIES set_tests_properties(cmake_fetch_content_build PROPERTIES
FIXTURES_REQUIRED cmake_fetch_content FIXTURES_REQUIRED cmake_fetch_content
LABELS git_required
) )
endif() endif()
@@ -4,9 +4,8 @@ project(DummyImport CXX)
include(FetchContent) include(FetchContent)
FetchContent_Declare(json get_filename_component(GIT_REPOSITORY_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../../.. ABSOLUTE)
GIT_REPOSITORY ${CMAKE_CURRENT_SOURCE_DIR}/../../.. FetchContent_Declare(json GIT_REPOSITORY ${GIT_REPOSITORY_DIRECTORY} GIT_TAG HEAD)
GIT_TAG HEAD)
FetchContent_GetProperties(json) FetchContent_GetProperties(json)
if(NOT json_POPULATED) if(NOT json_POPULATED)
+4 -4
View File
@@ -55,7 +55,7 @@ TEST_CASE("algorithms")
{ {
CHECK(std::any_of(j_array.begin(), j_array.end(), [](const json & value) CHECK(std::any_of(j_array.begin(), j_array.end(), [](const json & value)
{ {
return value.is_string() and value.get<std::string>() == "foo"; return value.is_string() && value.get<std::string>() == "foo";
})); }));
CHECK(std::any_of(j_object.begin(), j_object.end(), [](const json & value) CHECK(std::any_of(j_object.begin(), j_object.end(), [](const json & value)
{ {
@@ -139,14 +139,14 @@ TEST_CASE("algorithms")
{ {
CHECK(std::equal(j_array.begin(), j_array.end(), j_array.begin())); CHECK(std::equal(j_array.begin(), j_array.end(), j_array.begin()));
CHECK(std::equal(j_object.begin(), j_object.end(), j_object.begin())); CHECK(std::equal(j_object.begin(), j_object.end(), j_object.begin()));
CHECK(not std::equal(j_array.begin(), j_array.end(), j_object.begin())); CHECK(!std::equal(j_array.begin(), j_array.end(), j_object.begin()));
} }
SECTION("using user-defined comparison") SECTION("using user-defined comparison")
{ {
// compare objects only by size of its elements // compare objects only by size of its elements
json j_array2 = {13, 29, 3, {"Hello", "World"}, true, false, {{"one", 1}, {"two", 2}, {"three", 3}}, "foo", "baz"}; json j_array2 = {13, 29, 3, {"Hello", "World"}, true, false, {{"one", 1}, {"two", 2}, {"three", 3}}, "foo", "baz"};
CHECK(not std::equal(j_array.begin(), j_array.end(), j_array2.begin())); CHECK(!std::equal(j_array.begin(), j_array.end(), j_array2.begin()));
CHECK(std::equal(j_array.begin(), j_array.end(), j_array2.begin(), CHECK(std::equal(j_array.begin(), j_array.end(), j_array2.begin(),
[](const json & a, const json & b) [](const json & a, const json & b)
{ {
@@ -213,7 +213,7 @@ TEST_CASE("algorithms")
return v.is_string(); return v.is_string();
}); });
CHECK(std::distance(j_array.begin(), it) == 2); CHECK(std::distance(j_array.begin(), it) == 2);
CHECK(not it[2].is_string()); CHECK(!it[2].is_string());
} }
} }
+129
View File
@@ -0,0 +1,129 @@
/*
__ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 3.8.0
|_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
SPDX-License-Identifier: MIT
Copyright (c) 2018 Vitaliy Manushkin <agri@akamo.info>.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "doctest_compatibility.h"
#include <nlohmann/json.hpp>
TEST_CASE("Alternative number types")
{
SECTION("8 bit integers")
{
using json8 = nlohmann::basic_json<std::map, std::vector, std::string, bool, std::int8_t, std::uint8_t>;
SECTION("unsigned")
{
std::uint8_t unsigned_max = 255;
json8 j_unsigned_max = json8::parse("255");
CHECK(j_unsigned_max.is_number_unsigned());
CHECK(j_unsigned_max.dump() == "255");
CHECK((j_unsigned_max.get<std::uint8_t>() == unsigned_max));
CHECK(json8::parse(j_unsigned_max.dump()) == j_unsigned_max);
json8 j_overflow = json8::parse("256");
CHECK(j_overflow.is_number_float());
CHECK(j_overflow.dump() == "256.0");
}
SECTION("signed")
{
std::int8_t signed_min = -128;
json8 j_signed_min = json8::parse("-128");
CHECK(j_signed_min.is_number_integer());
CHECK(j_signed_min.dump() == "-128");
CHECK((j_signed_min.get<std::int8_t>() == signed_min));
CHECK(json8::parse(j_signed_min.dump()) == j_signed_min);
json8 j_underflow = json8::parse("-129");
CHECK(j_underflow.is_number_float());
CHECK(j_underflow.dump() == "-129.0");
}
}
SECTION("16 bit integers")
{
using json16 = nlohmann::basic_json<std::map, std::vector, std::string, bool, std::int16_t, std::uint16_t>;
SECTION("unsigned")
{
std::uint16_t unsigned_max = 65535;
json16 j_unsigned_max = json16::parse("65535");
CHECK(j_unsigned_max.is_number_unsigned());
CHECK(j_unsigned_max.dump() == "65535");
CHECK((j_unsigned_max.get<std::uint16_t>() == unsigned_max));
CHECK(json16::parse(j_unsigned_max.dump()) == j_unsigned_max);
json16 j_overflow = json16::parse("65536");
CHECK(j_overflow.is_number_float());
CHECK(j_overflow.dump() == "65536.0");
}
SECTION("signed")
{
std::int16_t signed_min = -32768;
json16 j_signed_min = json16::parse("-32768");
CHECK(j_signed_min.is_number_integer());
CHECK(j_signed_min.dump() == "-32768");
CHECK((j_signed_min.get<std::int16_t>() == signed_min));
CHECK(json16::parse(j_signed_min.dump()) == j_signed_min);
json16 j_underflow = json16::parse("-32769");
CHECK(j_underflow.is_number_float());
CHECK(j_underflow.dump() == "-32769.0");
}
}
// 128-bit arithmetic does not work with sanitizers
#if defined(__SIZEOF_INT128__) && !defined(__SANITIZE_ADDRESS__)
SECTION("128 bit integers")
{
using json128 = nlohmann::basic_json<std::map, std::vector, std::string, bool, __int128_t, __uint128_t>;
SECTION("unsigned")
{
__uint128_t unsigned_max = (340282366920938463463.374607431768211455) * std::pow(10, 18);
json128 j_unsigned_max = json128::parse("340282366920938463463374607431768211455");
CHECK(j_unsigned_max.is_number_unsigned());
CHECK(j_unsigned_max.dump() == "340282366920938463463374607431768211455");
//CHECK((j_unsigned_max.get<__uint128_t>() == unsigned_max));
CHECK(json128::parse(j_unsigned_max.dump()) == j_unsigned_max);
}
SECTION("signed")
{
__int128_t signed_min = (-170141183460469231731.687303715884105728) * std::pow(10, 18);
json128 j_signed_min = json128::parse("-170141183460469231731687303715884105728");
CHECK(j_signed_min.is_number_integer());
CHECK(j_signed_min.dump() == "-170141183460469231731687303715884105728");
CHECK((j_signed_min.get<__int128_t>() == signed_min));
CHECK(json128::parse(j_signed_min.dump()) == j_signed_min);
}
}
#endif
}
+65
View File
@@ -0,0 +1,65 @@
/*
__ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 3.8.0
|_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
SPDX-License-Identifier: MIT
Copyright (c) 2013-2019 Niels Lohmann <http://nlohmann.me>.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
// avoid warning when assert does not abort
#if defined(__GNUC__)
#pragma GCC diagnostic ignored "-Wstrict-overflow"
#endif
#include "doctest_compatibility.h"
/// global variable to record side effect of assert calls
static int assert_counter;
/// set failure variable to true instead of calling assert(x)
#define JSON_ASSERT(x) {if (!(x)) ++assert_counter; }
#include <nlohmann/json.hpp>
using nlohmann::json;
// the test assumes exceptions to work
#if !defined(JSON_NOEXCEPTION)
TEST_CASE("JSON_ASSERT(x)")
{
SECTION("basic_json(first, second)")
{
assert_counter = 0;
CHECK(assert_counter == 0);
json::iterator it;
json j;
// in case assertions do not abort execution, an exception is thrown
CHECK_THROWS_WITH_AS(json(it, j.end()), "[json.exception.invalid_iterator.201] iterators are not compatible", json::invalid_iterator);
// check that assertion actually happened
CHECK(assert_counter == 1);
}
}
#endif
+7 -7
View File
@@ -766,7 +766,7 @@ TEST_CASE("Incomplete BSON Input")
CHECK(json::from_bson(incomplete_bson, true, false).is_discarded()); CHECK(json::from_bson(incomplete_bson, true, false).is_discarded());
SaxCountdown scp(0); SaxCountdown scp(0);
CHECK(not json::sax_parse(incomplete_bson, &scp, json::input_format_t::bson)); CHECK(!json::sax_parse(incomplete_bson, &scp, json::input_format_t::bson));
} }
SECTION("Incomplete BSON Input 2") SECTION("Incomplete BSON Input 2")
@@ -784,7 +784,7 @@ TEST_CASE("Incomplete BSON Input")
CHECK(json::from_bson(incomplete_bson, true, false).is_discarded()); CHECK(json::from_bson(incomplete_bson, true, false).is_discarded());
SaxCountdown scp(0); SaxCountdown scp(0);
CHECK(not json::sax_parse(incomplete_bson, &scp, json::input_format_t::bson)); CHECK(!json::sax_parse(incomplete_bson, &scp, json::input_format_t::bson));
} }
SECTION("Incomplete BSON Input 3") SECTION("Incomplete BSON Input 3")
@@ -808,7 +808,7 @@ TEST_CASE("Incomplete BSON Input")
CHECK(json::from_bson(incomplete_bson, true, false).is_discarded()); CHECK(json::from_bson(incomplete_bson, true, false).is_discarded());
SaxCountdown scp(1); SaxCountdown scp(1);
CHECK(not json::sax_parse(incomplete_bson, &scp, json::input_format_t::bson)); CHECK(!json::sax_parse(incomplete_bson, &scp, json::input_format_t::bson));
} }
SECTION("Incomplete BSON Input 4") SECTION("Incomplete BSON Input 4")
@@ -825,7 +825,7 @@ TEST_CASE("Incomplete BSON Input")
CHECK(json::from_bson(incomplete_bson, true, false).is_discarded()); CHECK(json::from_bson(incomplete_bson, true, false).is_discarded());
SaxCountdown scp(0); SaxCountdown scp(0);
CHECK(not json::sax_parse(incomplete_bson, &scp, json::input_format_t::bson)); CHECK(!json::sax_parse(incomplete_bson, &scp, json::input_format_t::bson));
} }
SECTION("Improve coverage") SECTION("Improve coverage")
@@ -835,7 +835,7 @@ TEST_CASE("Incomplete BSON Input")
json j = {{"key", "value"}}; json j = {{"key", "value"}};
auto bson_vec = json::to_bson(j); auto bson_vec = json::to_bson(j);
SaxCountdown scp(2); SaxCountdown scp(2);
CHECK(not json::sax_parse(bson_vec, &scp, json::input_format_t::bson)); CHECK(!json::sax_parse(bson_vec, &scp, json::input_format_t::bson));
} }
SECTION("array") SECTION("array")
@@ -846,7 +846,7 @@ TEST_CASE("Incomplete BSON Input")
}; };
auto bson_vec = json::to_bson(j); auto bson_vec = json::to_bson(j);
SaxCountdown scp(2); SaxCountdown scp(2);
CHECK(not json::sax_parse(bson_vec, &scp, json::input_format_t::bson)); CHECK(!json::sax_parse(bson_vec, &scp, json::input_format_t::bson));
} }
} }
} }
@@ -887,7 +887,7 @@ TEST_CASE("Unsupported BSON input")
CHECK(json::from_bson(bson, true, false).is_discarded()); CHECK(json::from_bson(bson, true, false).is_discarded());
SaxCountdown scp(0); SaxCountdown scp(0);
CHECK(not json::sax_parse(bson, &scp, json::input_format_t::bson)); CHECK(!json::sax_parse(bson, &scp, json::input_format_t::bson));
} }
TEST_CASE("BSON numerical data") TEST_CASE("BSON numerical data")
+7 -7
View File
@@ -1077,7 +1077,7 @@ TEST_CASE("CBOR")
{ {
json j = json::from_cbor(std::vector<uint8_t>({0xf9, 0x7c, 0x00})); json j = json::from_cbor(std::vector<uint8_t>({0xf9, 0x7c, 0x00}));
json::number_float_t d = j; json::number_float_t d = j;
CHECK(not std::isfinite(d)); CHECK(!std::isfinite(d));
CHECK(j.dump() == "null"); CHECK(j.dump() == "null");
} }
@@ -1869,7 +1869,7 @@ TEST_CASE("CBOR")
{ {
const auto result = json::from_cbor(vec, false); const auto result = json::from_cbor(vec, false);
CHECK(result == json()); CHECK(result == json());
CHECK(not json::from_cbor(vec, false, false).is_discarded()); CHECK(!json::from_cbor(vec, false, false).is_discarded());
} }
SECTION("strict mode") SECTION("strict mode")
@@ -1889,21 +1889,21 @@ TEST_CASE("CBOR")
{ {
std::vector<uint8_t> v = {0x83, 0x01, 0x02, 0x03}; std::vector<uint8_t> v = {0x83, 0x01, 0x02, 0x03};
SaxCountdown scp(0); SaxCountdown scp(0);
CHECK(not json::sax_parse(v, &scp, json::input_format_t::cbor)); CHECK(!json::sax_parse(v, &scp, json::input_format_t::cbor));
} }
SECTION("start_object(len)") SECTION("start_object(len)")
{ {
std::vector<uint8_t> v = {0xA1, 0x63, 0x66, 0x6F, 0x6F, 0xF4}; std::vector<uint8_t> v = {0xA1, 0x63, 0x66, 0x6F, 0x6F, 0xF4};
SaxCountdown scp(0); SaxCountdown scp(0);
CHECK(not json::sax_parse(v, &scp, json::input_format_t::cbor)); CHECK(!json::sax_parse(v, &scp, json::input_format_t::cbor));
} }
SECTION("key()") SECTION("key()")
{ {
std::vector<uint8_t> v = {0xA1, 0x63, 0x66, 0x6F, 0x6F, 0xF4}; std::vector<uint8_t> v = {0xA1, 0x63, 0x66, 0x6F, 0x6F, 0xF4};
SaxCountdown scp(1); SaxCountdown scp(1);
CHECK(not json::sax_parse(v, &scp, json::input_format_t::cbor)); CHECK(!json::sax_parse(v, &scp, json::input_format_t::cbor));
} }
} }
} }
@@ -1954,7 +1954,7 @@ TEST_CASE("single CBOR roundtrip")
} }
} }
#if not defined(JSON_NOEXCEPTION) #if !defined(JSON_NOEXCEPTION)
TEST_CASE("CBOR regressions") TEST_CASE("CBOR regressions")
{ {
SECTION("fuzz test results") SECTION("fuzz test results")
@@ -2274,7 +2274,7 @@ TEST_CASE("CBOR roundtrips" * doctest::skip())
} }
} }
#if not defined(JSON_NOEXCEPTION) #if !defined(JSON_NOEXCEPTION)
TEST_CASE("all CBOR first bytes") TEST_CASE("all CBOR first bytes")
{ {
// these bytes will fail immediately with exception parse_error.112 // these bytes will fail immediately with exception parse_error.112
+6 -6
View File
@@ -224,7 +224,7 @@ TEST_CASE("const_iterator class")
json::const_iterator it = j.cbegin(); json::const_iterator it = j.cbegin();
CHECK((it.m_it.primitive_iterator.m_it == 1)); CHECK((it.m_it.primitive_iterator.m_it == 1));
it++; it++;
CHECK((it.m_it.primitive_iterator.m_it != 0 and it.m_it.primitive_iterator.m_it != 1)); CHECK((it.m_it.primitive_iterator.m_it != 0 && it.m_it.primitive_iterator.m_it != 1));
} }
SECTION("number") SECTION("number")
@@ -235,7 +235,7 @@ TEST_CASE("const_iterator class")
it++; it++;
CHECK((it.m_it.primitive_iterator.m_it == 1)); CHECK((it.m_it.primitive_iterator.m_it == 1));
it++; it++;
CHECK((it.m_it.primitive_iterator.m_it != 0 and it.m_it.primitive_iterator.m_it != 1)); CHECK((it.m_it.primitive_iterator.m_it != 0 && it.m_it.primitive_iterator.m_it != 1));
} }
SECTION("object") SECTION("object")
@@ -275,7 +275,7 @@ TEST_CASE("const_iterator class")
json::const_iterator it = j.cbegin(); json::const_iterator it = j.cbegin();
CHECK((it.m_it.primitive_iterator.m_it == 1)); CHECK((it.m_it.primitive_iterator.m_it == 1));
++it; ++it;
CHECK((it.m_it.primitive_iterator.m_it != 0 and it.m_it.primitive_iterator.m_it != 1)); CHECK((it.m_it.primitive_iterator.m_it != 0 && it.m_it.primitive_iterator.m_it != 1));
} }
SECTION("number") SECTION("number")
@@ -286,7 +286,7 @@ TEST_CASE("const_iterator class")
++it; ++it;
CHECK((it.m_it.primitive_iterator.m_it == 1)); CHECK((it.m_it.primitive_iterator.m_it == 1));
++it; ++it;
CHECK((it.m_it.primitive_iterator.m_it != 0 and it.m_it.primitive_iterator.m_it != 1)); CHECK((it.m_it.primitive_iterator.m_it != 0 && it.m_it.primitive_iterator.m_it != 1));
} }
SECTION("object") SECTION("object")
@@ -335,7 +335,7 @@ TEST_CASE("const_iterator class")
it--; it--;
CHECK((it.m_it.primitive_iterator.m_it == 0)); CHECK((it.m_it.primitive_iterator.m_it == 0));
it--; it--;
CHECK((it.m_it.primitive_iterator.m_it != 0 and it.m_it.primitive_iterator.m_it != 1)); CHECK((it.m_it.primitive_iterator.m_it != 0 && it.m_it.primitive_iterator.m_it != 1));
} }
SECTION("object") SECTION("object")
@@ -384,7 +384,7 @@ TEST_CASE("const_iterator class")
--it; --it;
CHECK((it.m_it.primitive_iterator.m_it == 0)); CHECK((it.m_it.primitive_iterator.m_it == 0));
--it; --it;
CHECK((it.m_it.primitive_iterator.m_it != 0 and it.m_it.primitive_iterator.m_it != 1)); CHECK((it.m_it.primitive_iterator.m_it != 0 && it.m_it.primitive_iterator.m_it != 1));
} }
SECTION("object") SECTION("object")
+6 -6
View File
@@ -208,7 +208,7 @@ TEST_CASE("iterator class")
json::iterator it = j.begin(); json::iterator it = j.begin();
CHECK((it.m_it.primitive_iterator.m_it == 1)); CHECK((it.m_it.primitive_iterator.m_it == 1));
it++; it++;
CHECK((it.m_it.primitive_iterator.m_it != 0 and it.m_it.primitive_iterator.m_it != 1)); CHECK((it.m_it.primitive_iterator.m_it != 0 && it.m_it.primitive_iterator.m_it != 1));
} }
SECTION("number") SECTION("number")
@@ -219,7 +219,7 @@ TEST_CASE("iterator class")
it++; it++;
CHECK((it.m_it.primitive_iterator.m_it == 1)); CHECK((it.m_it.primitive_iterator.m_it == 1));
it++; it++;
CHECK((it.m_it.primitive_iterator.m_it != 0 and it.m_it.primitive_iterator.m_it != 1)); CHECK((it.m_it.primitive_iterator.m_it != 0 && it.m_it.primitive_iterator.m_it != 1));
} }
SECTION("object") SECTION("object")
@@ -259,7 +259,7 @@ TEST_CASE("iterator class")
json::iterator it = j.begin(); json::iterator it = j.begin();
CHECK((it.m_it.primitive_iterator.m_it == 1)); CHECK((it.m_it.primitive_iterator.m_it == 1));
++it; ++it;
CHECK((it.m_it.primitive_iterator.m_it != 0 and it.m_it.primitive_iterator.m_it != 1)); CHECK((it.m_it.primitive_iterator.m_it != 0 && it.m_it.primitive_iterator.m_it != 1));
} }
SECTION("number") SECTION("number")
@@ -270,7 +270,7 @@ TEST_CASE("iterator class")
++it; ++it;
CHECK((it.m_it.primitive_iterator.m_it == 1)); CHECK((it.m_it.primitive_iterator.m_it == 1));
++it; ++it;
CHECK((it.m_it.primitive_iterator.m_it != 0 and it.m_it.primitive_iterator.m_it != 1)); CHECK((it.m_it.primitive_iterator.m_it != 0 && it.m_it.primitive_iterator.m_it != 1));
} }
SECTION("object") SECTION("object")
@@ -319,7 +319,7 @@ TEST_CASE("iterator class")
it--; it--;
CHECK((it.m_it.primitive_iterator.m_it == 0)); CHECK((it.m_it.primitive_iterator.m_it == 0));
it--; it--;
CHECK((it.m_it.primitive_iterator.m_it != 0 and it.m_it.primitive_iterator.m_it != 1)); CHECK((it.m_it.primitive_iterator.m_it != 0 && it.m_it.primitive_iterator.m_it != 1));
} }
SECTION("object") SECTION("object")
@@ -368,7 +368,7 @@ TEST_CASE("iterator class")
--it; --it;
CHECK((it.m_it.primitive_iterator.m_it == 0)); CHECK((it.m_it.primitive_iterator.m_it == 0));
--it; --it;
CHECK((it.m_it.primitive_iterator.m_it != 0 and it.m_it.primitive_iterator.m_it != 1)); CHECK((it.m_it.primitive_iterator.m_it != 0 && it.m_it.primitive_iterator.m_it != 1));
} }
SECTION("object") SECTION("object")
+66 -3
View File
@@ -37,14 +37,23 @@ using nlohmann::json;
namespace namespace
{ {
// shortcut to scan a string literal // shortcut to scan a string literal
json::lexer::token_type scan_string(const char* s); json::lexer::token_type scan_string(const char* s, const bool ignore_comments = false);
json::lexer::token_type scan_string(const char* s) json::lexer::token_type scan_string(const char* s, const bool ignore_comments)
{ {
auto ia = nlohmann::detail::input_adapter(s); auto ia = nlohmann::detail::input_adapter(s);
return nlohmann::detail::lexer<json, decltype(ia)>(std::move(ia)).scan(); return nlohmann::detail::lexer<json, decltype(ia)>(std::move(ia), ignore_comments).scan();
} }
} }
std::string get_error_message(const char* s, const bool ignore_comments = false);
std::string get_error_message(const char* s, const bool ignore_comments)
{
auto ia = nlohmann::detail::input_adapter(s);
auto lexer = nlohmann::detail::lexer<json, decltype(ia)>(std::move(ia), ignore_comments);
lexer.scan();
return lexer.get_error_message();
}
TEST_CASE("lexer class") TEST_CASE("lexer class")
{ {
SECTION("scan") SECTION("scan")
@@ -127,6 +136,8 @@ TEST_CASE("lexer class")
// store scan() result // store scan() result
const auto res = scan_string(s.c_str()); const auto res = scan_string(s.c_str());
CAPTURE(s);
switch (c) switch (c)
{ {
// single characters that are valid tokens // single characters that are valid tokens
@@ -179,4 +190,56 @@ TEST_CASE("lexer class")
s += "\""; s += "\"";
CHECK((scan_string(s.c_str()) == json::lexer::token_type::value_string)); CHECK((scan_string(s.c_str()) == json::lexer::token_type::value_string));
} }
SECTION("fail on comments")
{
CHECK((scan_string("/", false) == json::lexer::token_type::parse_error));
CHECK(get_error_message("/", false) == "invalid literal");
CHECK((scan_string("/!", false) == json::lexer::token_type::parse_error));
CHECK(get_error_message("/!", false) == "invalid literal");
CHECK((scan_string("/*", false) == json::lexer::token_type::parse_error));
CHECK(get_error_message("/*", false) == "invalid literal");
CHECK((scan_string("/**", false) == json::lexer::token_type::parse_error));
CHECK(get_error_message("/**", false) == "invalid literal");
CHECK((scan_string("//", false) == json::lexer::token_type::parse_error));
CHECK(get_error_message("//", false) == "invalid literal");
CHECK((scan_string("/**/", false) == json::lexer::token_type::parse_error));
CHECK(get_error_message("/**/", false) == "invalid literal");
CHECK((scan_string("/** /", false) == json::lexer::token_type::parse_error));
CHECK(get_error_message("/** /", false) == "invalid literal");
CHECK((scan_string("/***/", false) == json::lexer::token_type::parse_error));
CHECK(get_error_message("/***/", false) == "invalid literal");
CHECK((scan_string("/* true */", false) == json::lexer::token_type::parse_error));
CHECK(get_error_message("/* true */", false) == "invalid literal");
CHECK((scan_string("/*/**/", false) == json::lexer::token_type::parse_error));
CHECK(get_error_message("/*/**/", false) == "invalid literal");
CHECK((scan_string("/*/* */", false) == json::lexer::token_type::parse_error));
CHECK(get_error_message("/*/* */", false) == "invalid literal");
}
SECTION("ignore comments")
{
CHECK((scan_string("/", true) == json::lexer::token_type::parse_error));
CHECK(get_error_message("/", true) == "invalid comment; expecting '/' or '*' after '/'");
CHECK((scan_string("/!", true) == json::lexer::token_type::parse_error));
CHECK(get_error_message("/!", true) == "invalid comment; expecting '/' or '*' after '/'");
CHECK((scan_string("/*", true) == json::lexer::token_type::parse_error));
CHECK(get_error_message("/*", true) == "invalid comment; missing closing '*/'");
CHECK((scan_string("/**", true) == json::lexer::token_type::parse_error));
CHECK(get_error_message("/**", true) == "invalid comment; missing closing '*/'");
CHECK((scan_string("//", true) == json::lexer::token_type::end_of_input));
CHECK((scan_string("/**/", true) == json::lexer::token_type::end_of_input));
CHECK((scan_string("/** /", true) == json::lexer::token_type::parse_error));
CHECK(get_error_message("/** /", true) == "invalid comment; missing closing '*/'");
CHECK((scan_string("/***/", true) == json::lexer::token_type::end_of_input));
CHECK((scan_string("/* true */", true) == json::lexer::token_type::end_of_input));
CHECK((scan_string("/*/**/", true) == json::lexer::token_type::end_of_input));
CHECK((scan_string("/*/* */", true) == json::lexer::token_type::end_of_input));
}
} }
+57 -8
View File
@@ -224,6 +224,7 @@ class SaxCountdown : public nlohmann::json::json_sax_t
json parser_helper(const std::string& s); json parser_helper(const std::string& s);
bool accept_helper(const std::string& s); bool accept_helper(const std::string& s);
void comments_helper(const std::string& s);
json parser_helper(const std::string& s) json parser_helper(const std::string& s)
{ {
@@ -241,6 +242,8 @@ json parser_helper(const std::string& s)
json::sax_parse(s, &sdp); json::sax_parse(s, &sdp);
CHECK(j_sax == j); CHECK(j_sax == j);
comments_helper(s);
return j; return j;
} }
@@ -251,7 +254,7 @@ bool accept_helper(const std::string& s)
// 1. parse s without exceptions // 1. parse s without exceptions
json j; json j;
CHECK_NOTHROW(json::parser(nlohmann::detail::input_adapter(s), nullptr, false).parse(true, j)); CHECK_NOTHROW(json::parser(nlohmann::detail::input_adapter(s), nullptr, false).parse(true, j));
const bool ok_noexcept = not j.is_discarded(); const bool ok_noexcept = !j.is_discarded();
// 2. accept s // 2. accept s
const bool ok_accept = json::parser(nlohmann::detail::input_adapter(s)).accept(true); const bool ok_accept = json::parser(nlohmann::detail::input_adapter(s)).accept(true);
@@ -262,7 +265,7 @@ bool accept_helper(const std::string& s)
// 4. parse with SAX (compare with relaxed accept result) // 4. parse with SAX (compare with relaxed accept result)
SaxEventLogger el; SaxEventLogger el;
CHECK_NOTHROW(json::sax_parse(s, &el, json::input_format_t::json, false)); CHECK_NOTHROW(json::sax_parse(s, &el, json::input_format_t::json, false));
CHECK(json::parser(nlohmann::detail::input_adapter(s)).accept(false) == not el.errored); CHECK(json::parser(nlohmann::detail::input_adapter(s)).accept(false) == !el.errored);
// 5. parse with simple callback // 5. parse with simple callback
json::parser_callback_t cb = [](int, json::parse_event_t, json&) json::parser_callback_t cb = [](int, json::parse_event_t, json&)
@@ -270,15 +273,55 @@ bool accept_helper(const std::string& s)
return true; return true;
}; };
json j_cb = json::parse(s, cb, false); json j_cb = json::parse(s, cb, false);
const bool ok_noexcept_cb = not j_cb.is_discarded(); const bool ok_noexcept_cb = !j_cb.is_discarded();
// 6. check if this approach came to the same result // 6. check if this approach came to the same result
CHECK(ok_noexcept == ok_noexcept_cb); CHECK(ok_noexcept == ok_noexcept_cb);
// 7. return result // 7. check if comments are properly ignored
if (ok_accept)
{
comments_helper(s);
}
// 8. return result
return ok_accept; return ok_accept;
} }
void comments_helper(const std::string& s)
{
json _;
// parse/accept with default parser
CHECK_NOTHROW(_ = json::parse(s));
CHECK(json::accept(s));
// parse/accept while skipping comments
CHECK_NOTHROW(_ = json::parse(s, nullptr, false, true));
CHECK(json::accept(s, true));
std::vector<std::string> json_with_comments;
// start with a comment
json_with_comments.push_back(std::string("// this is a comment\n") + s);
json_with_comments.push_back(std::string("/* this is a comment */") + s);
// end with a comment
json_with_comments.push_back(s + "// this is a comment");
json_with_comments.push_back(s + "/* this is a comment */");
// check all strings
for (const auto& json_with_comment : json_with_comments)
{
CAPTURE(json_with_comment)
CHECK_THROWS_AS(_ = json::parse(json_with_comment), json::parse_error);
CHECK(!json::accept(json_with_comment));
CHECK_NOTHROW(_ = json::parse(json_with_comment, nullptr, true, true));
CHECK(json::accept(json_with_comment, true));
} }
}
} // namespace
TEST_CASE("parser class") TEST_CASE("parser class")
{ {
@@ -898,7 +941,7 @@ TEST_CASE("parser class")
SECTION("overflow") SECTION("overflow")
{ {
// overflows during parsing // overflows during parsing
CHECK(not accept_helper("1.18973e+4932")); CHECK(!accept_helper("1.18973e+4932"));
} }
SECTION("invalid numbers") SECTION("invalid numbers")
@@ -1573,7 +1616,7 @@ TEST_CASE("parser class")
{ {
json j_filtered1 = json::parse(structured_array, [](int, json::parse_event_t e, const json & parsed) json j_filtered1 = json::parse(structured_array, [](int, json::parse_event_t e, const json & parsed)
{ {
if (e == json::parse_event_t::object_end and parsed.contains("foo")) if (e == json::parse_event_t::object_end && parsed.contains("foo"))
{ {
return false; return false;
} }
@@ -1612,7 +1655,7 @@ TEST_CASE("parser class")
json j_object = json::parse(s_object, [](int, json::parse_event_t e, const json&) json j_object = json::parse(s_object, [](int, json::parse_event_t e, const json&)
{ {
static bool first = true; static bool first = true;
if (e == json::parse_event_t::object_end and first) if (e == json::parse_event_t::object_end && first)
{ {
first = false; first = false;
return false; return false;
@@ -1631,7 +1674,7 @@ TEST_CASE("parser class")
json j_array = json::parse(s_array, [](int, json::parse_event_t e, const json&) json j_array = json::parse(s_array, [](int, json::parse_event_t e, const json&)
{ {
static bool first = true; static bool first = true;
if (e == json::parse_event_t::array_end and first) if (e == json::parse_event_t::array_end && first)
{ {
first = false; first = false;
return false; return false;
@@ -1834,4 +1877,10 @@ TEST_CASE("parser class")
} }
} }
} }
SECTION("error messages for comments")
{
CHECK_THROWS_WITH_AS(json::parse("/a", nullptr, true, true), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid comment; expecting '/' or '*' after '/'; last read: '/a'", json::parse_error);
CHECK_THROWS_WITH_AS(json::parse("/*", nullptr, true, true), "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid comment; missing closing '*/'; last read: '/*<U+0000>'", json::parse_error);
}
} }
+5 -5
View File
@@ -165,7 +165,7 @@ TEST_CASE("lexicographical comparison operators")
CAPTURE(i) CAPTURE(i)
CAPTURE(j) CAPTURE(j)
// check definition // check definition
CHECK( (j_values[i] != j_values[j]) == not(j_values[i] == j_values[j]) ); CHECK( (j_values[i] != j_values[j]) == !(j_values[i] == j_values[j]) );
} }
} }
@@ -173,8 +173,8 @@ TEST_CASE("lexicographical comparison operators")
json j_null; json j_null;
CHECK( (j_null != nullptr) == false); CHECK( (j_null != nullptr) == false);
CHECK( (nullptr != j_null) == false); CHECK( (nullptr != j_null) == false);
CHECK( (j_null != nullptr) == not(j_null == nullptr)); CHECK( (j_null != nullptr) == !(j_null == nullptr));
CHECK( (nullptr != j_null) == not(nullptr == j_null)); CHECK( (nullptr != j_null) == !(nullptr == j_null));
} }
SECTION("comparison: less") SECTION("comparison: less")
@@ -234,7 +234,7 @@ TEST_CASE("lexicographical comparison operators")
CAPTURE(i) CAPTURE(i)
CAPTURE(j) CAPTURE(j)
// check definition // check definition
CHECK( (j_values[i] <= j_values[j]) == not(j_values[j] < j_values[i]) ); CHECK( (j_values[i] <= j_values[j]) == !(j_values[j] < j_values[i]) );
} }
} }
} }
@@ -262,7 +262,7 @@ TEST_CASE("lexicographical comparison operators")
CAPTURE(i) CAPTURE(i)
CAPTURE(j) CAPTURE(j)
// check definition // check definition
CHECK( (j_values[i] >= j_values[j]) == not(j_values[i] < j_values[j]) ); CHECK( (j_values[i] >= j_values[j]) == !(j_values[i] < j_values[j]) );
} }
} }
} }
+2 -2
View File
@@ -154,7 +154,7 @@ TEST_CASE("concepts")
json j {1, 2, 3}; json j {1, 2, 3};
json::iterator it1 = j.begin(); json::iterator it1 = j.begin();
json::iterator it2 = j.end(); json::iterator it2 = j.end();
std::swap(it1, it2); swap(it1, it2);
CHECK(it1 == j.end()); CHECK(it1 == j.end());
CHECK(it2 == j.begin()); CHECK(it2 == j.begin());
} }
@@ -162,7 +162,7 @@ TEST_CASE("concepts")
json j {1, 2, 3}; json j {1, 2, 3};
json::const_iterator it1 = j.cbegin(); json::const_iterator it1 = j.cbegin();
json::const_iterator it2 = j.cend(); json::const_iterator it2 = j.cend();
std::swap(it1, it2); swap(it1, it2);
CHECK(it1 == j.end()); CHECK(it1 == j.end());
CHECK(it2 == j.begin()); CHECK(it2 == j.begin());
} }
+1 -1
View File
@@ -847,7 +847,7 @@ TEST_CASE("constructors")
// check round trip of NaN // check round trip of NaN
json::number_float_t d = j; json::number_float_t d = j;
CHECK((std::isnan(d) and std::isnan(n)) == true); CHECK((std::isnan(d) && std::isnan(n)) == true);
// check that NaN is serialized to null // check that NaN is serialized to null
CHECK(j.dump() == "null"); CHECK(j.dump() == "null");
+1 -1
View File
@@ -272,7 +272,7 @@ TEST_CASE("value conversion")
json(json::value_t::null).get<std::vector<json>>(), json(json::value_t::null).get<std::vector<json>>(),
"[json.exception.type_error.302] type must be array, but is null"); "[json.exception.type_error.302] type must be array, but is null");
#if not defined(JSON_NOEXCEPTION) #if !defined(JSON_NOEXCEPTION)
SECTION("reserve is called on containers that supports it") SECTION("reserve is called on containers that supports it")
{ {
// make sure all values are properly copied // make sure all values are properly copied
+47 -47
View File
@@ -289,14 +289,14 @@ TEST_CASE("deserialization")
CHECK_THROWS_AS(_ = json::parse(ss1), json::parse_error&); CHECK_THROWS_AS(_ = json::parse(ss1), json::parse_error&);
CHECK_THROWS_WITH(_ = json::parse(ss2), CHECK_THROWS_WITH(_ = json::parse(ss2),
"[json.exception.parse_error.101] parse error at line 1, column 29: syntax error while parsing array - unexpected end of input; expected ']'"); "[json.exception.parse_error.101] parse error at line 1, column 29: syntax error while parsing array - unexpected end of input; expected ']'");
CHECK(not json::accept(ss3)); CHECK(!json::accept(ss3));
json j_error; json j_error;
CHECK_NOTHROW(j_error = json::parse(ss4, nullptr, false)); CHECK_NOTHROW(j_error = json::parse(ss4, nullptr, false));
CHECK(j_error.is_discarded()); CHECK(j_error.is_discarded());
SaxEventLogger l; SaxEventLogger l;
CHECK(not json::sax_parse(ss5, &l)); CHECK(!json::sax_parse(ss5, &l));
CHECK(l.events.size() == 11); CHECK(l.events.size() == 11);
CHECK(l.events == std::vector<std::string>( CHECK(l.events == std::vector<std::string>(
{ {
@@ -314,14 +314,14 @@ TEST_CASE("deserialization")
CHECK_THROWS_AS(_ = json::parse(s), json::parse_error&); CHECK_THROWS_AS(_ = json::parse(s), json::parse_error&);
CHECK_THROWS_WITH(_ = json::parse(s), CHECK_THROWS_WITH(_ = json::parse(s),
"[json.exception.parse_error.101] parse error at line 1, column 29: syntax error while parsing array - unexpected end of input; expected ']'"); "[json.exception.parse_error.101] parse error at line 1, column 29: syntax error while parsing array - unexpected end of input; expected ']'");
CHECK(not json::accept(s)); CHECK(!json::accept(s));
json j_error; json j_error;
CHECK_NOTHROW(j_error = json::parse(s, nullptr, false)); CHECK_NOTHROW(j_error = json::parse(s, nullptr, false));
CHECK(j_error.is_discarded()); CHECK(j_error.is_discarded());
SaxEventLogger l; SaxEventLogger l;
CHECK(not json::sax_parse(s, &l)); CHECK(!json::sax_parse(s, &l));
CHECK(l.events.size() == 11); CHECK(l.events.size() == 11);
CHECK(l.events == std::vector<std::string>( CHECK(l.events == std::vector<std::string>(
{ {
@@ -450,10 +450,10 @@ TEST_CASE("deserialization")
std::vector<uint8_t> v; std::vector<uint8_t> v;
json _; json _;
CHECK_THROWS_AS(_ = json::parse(v), json::parse_error&); CHECK_THROWS_AS(_ = json::parse(v), json::parse_error&);
CHECK(not json::accept(v)); CHECK(!json::accept(v));
SaxEventLogger l; SaxEventLogger l;
CHECK(not json::sax_parse(v, &l)); CHECK(!json::sax_parse(v, &l));
CHECK(l.events.size() == 1); CHECK(l.events.size() == 1);
CHECK(l.events == std::vector<std::string>({"parse_error(1)"})); CHECK(l.events == std::vector<std::string>({"parse_error(1)"}));
} }
@@ -538,10 +538,10 @@ TEST_CASE("deserialization")
{ {
std::vector<uint8_t> v; std::vector<uint8_t> v;
CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&);
CHECK(not json::accept(std::begin(v), std::end(v))); CHECK(!json::accept(std::begin(v), std::end(v)));
SaxEventLogger l; SaxEventLogger l;
CHECK(not json::sax_parse(std::begin(v), std::end(v), &l)); CHECK(!json::sax_parse(std::begin(v), std::end(v), &l));
CHECK(l.events.size() == 1); CHECK(l.events.size() == 1);
CHECK(l.events == std::vector<std::string>({"parse_error(1)"})); CHECK(l.events == std::vector<std::string>({"parse_error(1)"}));
} }
@@ -554,14 +554,14 @@ TEST_CASE("deserialization")
{ {
uint8_t v[] = {'\"', 'a', 'a', 'a', 'a', 'a', 'a', '\\', 'u'}; uint8_t v[] = {'\"', 'a', 'a', 'a', 'a', 'a', 'a', '\\', 'u'};
CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&);
CHECK(not json::accept(std::begin(v), std::end(v))); CHECK(!json::accept(std::begin(v), std::end(v)));
json j_error; json j_error;
CHECK_NOTHROW(j_error = json::parse(std::begin(v), std::end(v), nullptr, false)); CHECK_NOTHROW(j_error = json::parse(std::begin(v), std::end(v), nullptr, false));
CHECK(j_error.is_discarded()); CHECK(j_error.is_discarded());
SaxEventLogger l; SaxEventLogger l;
CHECK(not json::sax_parse(std::begin(v), std::end(v), &l)); CHECK(!json::sax_parse(std::begin(v), std::end(v), &l));
CHECK(l.events.size() == 1); CHECK(l.events.size() == 1);
CHECK(l.events == std::vector<std::string>({"parse_error(10)"})); CHECK(l.events == std::vector<std::string>({"parse_error(10)"}));
} }
@@ -570,14 +570,14 @@ TEST_CASE("deserialization")
{ {
uint8_t v[] = {'\"', 'a', 'a', 'a', 'a', 'a', 'a', '\\', 'u', '1'}; uint8_t v[] = {'\"', 'a', 'a', 'a', 'a', 'a', 'a', '\\', 'u', '1'};
CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&);
CHECK(not json::accept(std::begin(v), std::end(v))); CHECK(!json::accept(std::begin(v), std::end(v)));
json j_error; json j_error;
CHECK_NOTHROW(j_error = json::parse(std::begin(v), std::end(v), nullptr, false)); CHECK_NOTHROW(j_error = json::parse(std::begin(v), std::end(v), nullptr, false));
CHECK(j_error.is_discarded()); CHECK(j_error.is_discarded());
SaxEventLogger l; SaxEventLogger l;
CHECK(not json::sax_parse(std::begin(v), std::end(v), &l)); CHECK(!json::sax_parse(std::begin(v), std::end(v), &l));
CHECK(l.events.size() == 1); CHECK(l.events.size() == 1);
CHECK(l.events == std::vector<std::string>({"parse_error(11)"})); CHECK(l.events == std::vector<std::string>({"parse_error(11)"}));
} }
@@ -586,14 +586,14 @@ TEST_CASE("deserialization")
{ {
uint8_t v[] = {'\"', 'a', 'a', 'a', 'a', 'a', 'a', '\\', 'u', '1', '1', '1', '1', '1', '1', '1', '1'}; uint8_t v[] = {'\"', 'a', 'a', 'a', 'a', 'a', 'a', '\\', 'u', '1', '1', '1', '1', '1', '1', '1', '1'};
CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&);
CHECK(not json::accept(std::begin(v), std::end(v))); CHECK(!json::accept(std::begin(v), std::end(v)));
json j_error; json j_error;
CHECK_NOTHROW(j_error = json::parse(std::begin(v), std::end(v), nullptr, false)); CHECK_NOTHROW(j_error = json::parse(std::begin(v), std::end(v), nullptr, false));
CHECK(j_error.is_discarded()); CHECK(j_error.is_discarded());
SaxEventLogger l; SaxEventLogger l;
CHECK(not json::sax_parse(std::begin(v), std::end(v), &l)); CHECK(!json::sax_parse(std::begin(v), std::end(v), &l));
CHECK(l.events.size() == 1); CHECK(l.events.size() == 1);
CHECK(l.events == std::vector<std::string>({"parse_error(18)"})); CHECK(l.events == std::vector<std::string>({"parse_error(18)"}));
} }
@@ -602,14 +602,14 @@ TEST_CASE("deserialization")
{ {
uint8_t v[] = {'\"', 'a', 'a', 'a', 'a', 'a', 'a', 'u', '1', '1', '1', '1', '1', '1', '1', '1', '\\'}; uint8_t v[] = {'\"', 'a', 'a', 'a', 'a', 'a', 'a', 'u', '1', '1', '1', '1', '1', '1', '1', '1', '\\'};
CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&);
CHECK(not json::accept(std::begin(v), std::end(v))); CHECK(!json::accept(std::begin(v), std::end(v)));
json j_error; json j_error;
CHECK_NOTHROW(j_error = json::parse(std::begin(v), std::end(v), nullptr, false)); CHECK_NOTHROW(j_error = json::parse(std::begin(v), std::end(v), nullptr, false));
CHECK(j_error.is_discarded()); CHECK(j_error.is_discarded());
SaxEventLogger l; SaxEventLogger l;
CHECK(not json::sax_parse(std::begin(v), std::end(v), &l)); CHECK(!json::sax_parse(std::begin(v), std::end(v), &l));
CHECK(l.events.size() == 1); CHECK(l.events.size() == 1);
CHECK(l.events == std::vector<std::string>({"parse_error(18)"})); CHECK(l.events == std::vector<std::string>({"parse_error(18)"}));
} }
@@ -618,14 +618,14 @@ TEST_CASE("deserialization")
{ {
uint8_t v[] = {'\"', 0x7F, 0xC1}; uint8_t v[] = {'\"', 0x7F, 0xC1};
CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&);
CHECK(not json::accept(std::begin(v), std::end(v))); CHECK(!json::accept(std::begin(v), std::end(v)));
json j_error; json j_error;
CHECK_NOTHROW(j_error = json::parse(std::begin(v), std::end(v), nullptr, false)); CHECK_NOTHROW(j_error = json::parse(std::begin(v), std::end(v), nullptr, false));
CHECK(j_error.is_discarded()); CHECK(j_error.is_discarded());
SaxEventLogger l; SaxEventLogger l;
CHECK(not json::sax_parse(std::begin(v), std::end(v), &l)); CHECK(!json::sax_parse(std::begin(v), std::end(v), &l));
CHECK(l.events.size() == 1); CHECK(l.events.size() == 1);
CHECK(l.events == std::vector<std::string>({"parse_error(3)"})); CHECK(l.events == std::vector<std::string>({"parse_error(3)"}));
} }
@@ -637,14 +637,14 @@ TEST_CASE("deserialization")
CHECK_THROWS_AS(_ = json::parse(std::begin(v), std::end(v)), json::parse_error&); CHECK_THROWS_AS(_ = json::parse(std::begin(v), std::end(v)), json::parse_error&);
CHECK_THROWS_WITH(_ = json::parse(std::begin(v), std::end(v)), CHECK_THROWS_WITH(_ = json::parse(std::begin(v), std::end(v)),
"[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid string: ill-formed UTF-8 byte; last read: '\"\x7f\xdf\x7f'"); "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid string: ill-formed UTF-8 byte; last read: '\"\x7f\xdf\x7f'");
CHECK(not json::accept(std::begin(v), std::end(v))); CHECK(!json::accept(std::begin(v), std::end(v)));
json j_error; json j_error;
CHECK_NOTHROW(j_error = json::parse(std::begin(v), std::end(v), nullptr, false)); CHECK_NOTHROW(j_error = json::parse(std::begin(v), std::end(v), nullptr, false));
CHECK(j_error.is_discarded()); CHECK(j_error.is_discarded());
SaxEventLogger l; SaxEventLogger l;
CHECK(not json::sax_parse(std::begin(v), std::end(v), &l)); CHECK(!json::sax_parse(std::begin(v), std::end(v), &l));
CHECK(l.events.size() == 1); CHECK(l.events.size() == 1);
CHECK(l.events == std::vector<std::string>({"parse_error(4)"})); CHECK(l.events == std::vector<std::string>({"parse_error(4)"}));
} }
@@ -653,14 +653,14 @@ TEST_CASE("deserialization")
{ {
uint8_t v[] = {'\"', 0x7F, 0xDF, 0xC0}; uint8_t v[] = {'\"', 0x7F, 0xDF, 0xC0};
CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&);
CHECK(not json::accept(std::begin(v), std::end(v))); CHECK(!json::accept(std::begin(v), std::end(v)));
json j_error; json j_error;
CHECK_NOTHROW(j_error = json::parse(std::begin(v), std::end(v), nullptr, false)); CHECK_NOTHROW(j_error = json::parse(std::begin(v), std::end(v), nullptr, false));
CHECK(j_error.is_discarded()); CHECK(j_error.is_discarded());
SaxEventLogger l; SaxEventLogger l;
CHECK(not json::sax_parse(std::begin(v), std::end(v), &l)); CHECK(!json::sax_parse(std::begin(v), std::end(v), &l));
CHECK(l.events.size() == 1); CHECK(l.events.size() == 1);
CHECK(l.events == std::vector<std::string>({"parse_error(4)"})); CHECK(l.events == std::vector<std::string>({"parse_error(4)"}));
} }
@@ -669,14 +669,14 @@ TEST_CASE("deserialization")
{ {
uint8_t v[] = {'\"', 0x7F, 0xE0, 0x9F}; uint8_t v[] = {'\"', 0x7F, 0xE0, 0x9F};
CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&);
CHECK(not json::accept(std::begin(v), std::end(v))); CHECK(!json::accept(std::begin(v), std::end(v)));
json j_error; json j_error;
CHECK_NOTHROW(j_error = json::parse(std::begin(v), std::end(v), nullptr, false)); CHECK_NOTHROW(j_error = json::parse(std::begin(v), std::end(v), nullptr, false));
CHECK(j_error.is_discarded()); CHECK(j_error.is_discarded());
SaxEventLogger l; SaxEventLogger l;
CHECK(not json::sax_parse(std::begin(v), std::end(v), &l)); CHECK(!json::sax_parse(std::begin(v), std::end(v), &l));
CHECK(l.events.size() == 1); CHECK(l.events.size() == 1);
CHECK(l.events == std::vector<std::string>({"parse_error(4)"})); CHECK(l.events == std::vector<std::string>({"parse_error(4)"}));
} }
@@ -685,14 +685,14 @@ TEST_CASE("deserialization")
{ {
uint8_t v[] = {'\"', 0x7F, 0xEF, 0xC0}; uint8_t v[] = {'\"', 0x7F, 0xEF, 0xC0};
CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&);
CHECK(not json::accept(std::begin(v), std::end(v))); CHECK(!json::accept(std::begin(v), std::end(v)));
json j_error; json j_error;
CHECK_NOTHROW(j_error = json::parse(std::begin(v), std::end(v), nullptr, false)); CHECK_NOTHROW(j_error = json::parse(std::begin(v), std::end(v), nullptr, false));
CHECK(j_error.is_discarded()); CHECK(j_error.is_discarded());
SaxEventLogger l; SaxEventLogger l;
CHECK(not json::sax_parse(std::begin(v), std::end(v), &l)); CHECK(!json::sax_parse(std::begin(v), std::end(v), &l));
CHECK(l.events.size() == 1); CHECK(l.events.size() == 1);
CHECK(l.events == std::vector<std::string>({"parse_error(4)"})); CHECK(l.events == std::vector<std::string>({"parse_error(4)"}));
} }
@@ -701,14 +701,14 @@ TEST_CASE("deserialization")
{ {
uint8_t v[] = {'\"', 0x7F, 0xED, 0x7F}; uint8_t v[] = {'\"', 0x7F, 0xED, 0x7F};
CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&);
CHECK(not json::accept(std::begin(v), std::end(v))); CHECK(!json::accept(std::begin(v), std::end(v)));
json j_error; json j_error;
CHECK_NOTHROW(j_error = json::parse(std::begin(v), std::end(v), nullptr, false)); CHECK_NOTHROW(j_error = json::parse(std::begin(v), std::end(v), nullptr, false));
CHECK(j_error.is_discarded()); CHECK(j_error.is_discarded());
SaxEventLogger l; SaxEventLogger l;
CHECK(not json::sax_parse(std::begin(v), std::end(v), &l)); CHECK(!json::sax_parse(std::begin(v), std::end(v), &l));
CHECK(l.events.size() == 1); CHECK(l.events.size() == 1);
CHECK(l.events == std::vector<std::string>({"parse_error(4)"})); CHECK(l.events == std::vector<std::string>({"parse_error(4)"}));
} }
@@ -717,14 +717,14 @@ TEST_CASE("deserialization")
{ {
uint8_t v[] = {'\"', 0x7F, 0xF0, 0x8F}; uint8_t v[] = {'\"', 0x7F, 0xF0, 0x8F};
CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&);
CHECK(not json::accept(std::begin(v), std::end(v))); CHECK(!json::accept(std::begin(v), std::end(v)));
json j_error; json j_error;
CHECK_NOTHROW(j_error = json::parse(std::begin(v), std::end(v), nullptr, false)); CHECK_NOTHROW(j_error = json::parse(std::begin(v), std::end(v), nullptr, false));
CHECK(j_error.is_discarded()); CHECK(j_error.is_discarded());
SaxEventLogger l; SaxEventLogger l;
CHECK(not json::sax_parse(std::begin(v), std::end(v), &l)); CHECK(!json::sax_parse(std::begin(v), std::end(v), &l));
CHECK(l.events.size() == 1); CHECK(l.events.size() == 1);
CHECK(l.events == std::vector<std::string>({"parse_error(4)"})); CHECK(l.events == std::vector<std::string>({"parse_error(4)"}));
} }
@@ -733,14 +733,14 @@ TEST_CASE("deserialization")
{ {
uint8_t v[] = {'\"', 0x7F, 0xF0, 0xC0}; uint8_t v[] = {'\"', 0x7F, 0xF0, 0xC0};
CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&);
CHECK(not json::accept(std::begin(v), std::end(v))); CHECK(!json::accept(std::begin(v), std::end(v)));
json j_error; json j_error;
CHECK_NOTHROW(j_error = json::parse(std::begin(v), std::end(v), nullptr, false)); CHECK_NOTHROW(j_error = json::parse(std::begin(v), std::end(v), nullptr, false));
CHECK(j_error.is_discarded()); CHECK(j_error.is_discarded());
SaxEventLogger l; SaxEventLogger l;
CHECK(not json::sax_parse(std::begin(v), std::end(v), &l)); CHECK(!json::sax_parse(std::begin(v), std::end(v), &l));
CHECK(l.events.size() == 1); CHECK(l.events.size() == 1);
CHECK(l.events == std::vector<std::string>({"parse_error(4)"})); CHECK(l.events == std::vector<std::string>({"parse_error(4)"}));
} }
@@ -749,14 +749,14 @@ TEST_CASE("deserialization")
{ {
uint8_t v[] = {'\"', 0x7F, 0xF3, 0x7F}; uint8_t v[] = {'\"', 0x7F, 0xF3, 0x7F};
CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&);
CHECK(not json::accept(std::begin(v), std::end(v))); CHECK(!json::accept(std::begin(v), std::end(v)));
json j_error; json j_error;
CHECK_NOTHROW(j_error = json::parse(std::begin(v), std::end(v), nullptr, false)); CHECK_NOTHROW(j_error = json::parse(std::begin(v), std::end(v), nullptr, false));
CHECK(j_error.is_discarded()); CHECK(j_error.is_discarded());
SaxEventLogger l; SaxEventLogger l;
CHECK(not json::sax_parse(std::begin(v), std::end(v), &l)); CHECK(!json::sax_parse(std::begin(v), std::end(v), &l));
CHECK(l.events.size() == 1); CHECK(l.events.size() == 1);
CHECK(l.events == std::vector<std::string>({"parse_error(4)"})); CHECK(l.events == std::vector<std::string>({"parse_error(4)"}));
} }
@@ -765,14 +765,14 @@ TEST_CASE("deserialization")
{ {
uint8_t v[] = {'\"', 0x7F, 0xF3, 0xC0}; uint8_t v[] = {'\"', 0x7F, 0xF3, 0xC0};
CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&);
CHECK(not json::accept(std::begin(v), std::end(v))); CHECK(!json::accept(std::begin(v), std::end(v)));
json j_error; json j_error;
CHECK_NOTHROW(j_error = json::parse(std::begin(v), std::end(v), nullptr, false)); CHECK_NOTHROW(j_error = json::parse(std::begin(v), std::end(v), nullptr, false));
CHECK(j_error.is_discarded()); CHECK(j_error.is_discarded());
SaxEventLogger l; SaxEventLogger l;
CHECK(not json::sax_parse(std::begin(v), std::end(v), &l)); CHECK(!json::sax_parse(std::begin(v), std::end(v), &l));
CHECK(l.events.size() == 1); CHECK(l.events.size() == 1);
CHECK(l.events == std::vector<std::string>({"parse_error(4)"})); CHECK(l.events == std::vector<std::string>({"parse_error(4)"}));
} }
@@ -781,14 +781,14 @@ TEST_CASE("deserialization")
{ {
uint8_t v[] = {'\"', 0x7F, 0xF4, 0x7F}; uint8_t v[] = {'\"', 0x7F, 0xF4, 0x7F};
CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&);
CHECK(not json::accept(std::begin(v), std::end(v))); CHECK(!json::accept(std::begin(v), std::end(v)));
json j_error; json j_error;
CHECK_NOTHROW(j_error = json::parse(std::begin(v), std::end(v), nullptr, false)); CHECK_NOTHROW(j_error = json::parse(std::begin(v), std::end(v), nullptr, false));
CHECK(j_error.is_discarded()); CHECK(j_error.is_discarded());
SaxEventLogger l; SaxEventLogger l;
CHECK(not json::sax_parse(std::begin(v), std::end(v), &l)); CHECK(!json::sax_parse(std::begin(v), std::end(v), &l));
CHECK(l.events.size() == 1); CHECK(l.events.size() == 1);
CHECK(l.events == std::vector<std::string>({"parse_error(4)"})); CHECK(l.events == std::vector<std::string>({"parse_error(4)"}));
} }
@@ -797,14 +797,14 @@ TEST_CASE("deserialization")
{ {
uint8_t v[] = {'{', '\"', '\"', ':', '1', '1'}; uint8_t v[] = {'{', '\"', '\"', ':', '1', '1'};
CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&);
CHECK(not json::accept(std::begin(v), std::end(v))); CHECK(!json::accept(std::begin(v), std::end(v)));
json j_error; json j_error;
CHECK_NOTHROW(j_error = json::parse(std::begin(v), std::end(v), nullptr, false)); CHECK_NOTHROW(j_error = json::parse(std::begin(v), std::end(v), nullptr, false));
CHECK(j_error.is_discarded()); CHECK(j_error.is_discarded());
SaxEventLogger l; SaxEventLogger l;
CHECK(not json::sax_parse(std::begin(v), std::end(v), &l)); CHECK(!json::sax_parse(std::begin(v), std::end(v), &l));
CHECK(l.events.size() == 4); CHECK(l.events.size() == 4);
CHECK(l.events == std::vector<std::string>( CHECK(l.events == std::vector<std::string>(
{ {
@@ -831,7 +831,7 @@ TEST_CASE("deserialization")
"[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal"); "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal");
SaxEventLogger l; SaxEventLogger l;
CHECK(not json::sax_parse(bom, &l)); CHECK(!json::sax_parse(bom, &l));
CHECK(l.events.size() == 1); CHECK(l.events.size() == 1);
CHECK(l.events == std::vector<std::string>( CHECK(l.events == std::vector<std::string>(
{ {
@@ -871,8 +871,8 @@ TEST_CASE("deserialization")
"[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid BOM; must be 0xEF 0xBB 0xBF if given; last read: '\xEF\xBB'"); "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid BOM; must be 0xEF 0xBB 0xBF if given; last read: '\xEF\xBB'");
SaxEventLogger l1, l2; SaxEventLogger l1, l2;
CHECK(not json::sax_parse(std::istringstream(bom.substr(0, 2)), &l1)); CHECK(!json::sax_parse(std::istringstream(bom.substr(0, 2)), &l1));
CHECK(not json::sax_parse(bom.substr(0, 2), &l2)); CHECK(!json::sax_parse(bom.substr(0, 2), &l2));
CHECK(l1.events.size() == 1); CHECK(l1.events.size() == 1);
CHECK(l1.events == std::vector<std::string>( CHECK(l1.events == std::vector<std::string>(
{ {
@@ -897,8 +897,8 @@ TEST_CASE("deserialization")
"[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid BOM; must be 0xEF 0xBB 0xBF if given; last read: '\xEF'"); "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid BOM; must be 0xEF 0xBB 0xBF if given; last read: '\xEF'");
SaxEventLogger l1, l2; SaxEventLogger l1, l2;
CHECK(not json::sax_parse(std::istringstream(bom.substr(0, 1)), &l1)); CHECK(!json::sax_parse(std::istringstream(bom.substr(0, 1)), &l1));
CHECK(not json::sax_parse(bom.substr(0, 1), &l2)); CHECK(!json::sax_parse(bom.substr(0, 1), &l2));
CHECK(l1.events.size() == 1); CHECK(l1.events.size() == 1);
CHECK(l1.events == std::vector<std::string>( CHECK(l1.events == std::vector<std::string>(
{ {
@@ -931,7 +931,7 @@ TEST_CASE("deserialization")
s.push_back(static_cast<char>(bom[1] + i1)); s.push_back(static_cast<char>(bom[1] + i1));
s.push_back(static_cast<char>(bom[2] + i2)); s.push_back(static_cast<char>(bom[2] + i2));
if (i0 == 0 and i1 == 0 and i2 == 0) if (i0 == 0 && i1 == 0 && i2 == 0)
{ {
// without any variation, we skip the BOM // without any variation, we skip the BOM
CHECK(json::parse(s + "null") == json()); CHECK(json::parse(s + "null") == json());
@@ -953,7 +953,7 @@ TEST_CASE("deserialization")
CHECK_THROWS_AS(_ = json::parse(std::istringstream(s + "null")), json::parse_error&); CHECK_THROWS_AS(_ = json::parse(std::istringstream(s + "null")), json::parse_error&);
SaxEventLogger l; SaxEventLogger l;
CHECK(not json::sax_parse(s + "null", &l)); CHECK(!json::sax_parse(s + "null", &l));
CHECK(l.events.size() == 1); CHECK(l.events.size() == 1);
if (i0 != 0) if (i0 != 0)
+1 -1
View File
@@ -1072,7 +1072,7 @@ TEST_CASE("element access 2")
} }
} }
#if not defined(JSON_NOEXCEPTION) #if !defined(JSON_NOEXCEPTION)
TEST_CASE("element access 2 (throwing tests)") TEST_CASE("element access 2 (throwing tests)")
{ {
SECTION("object") SECTION("object")
+107 -107
View File
@@ -43,36 +43,36 @@ TEST_CASE("object inspection")
SECTION("object") SECTION("object")
{ {
json j {{"foo", 1}, {"bar", false}}; json j {{"foo", 1}, {"bar", false}};
CHECK(not j.is_null()); CHECK(!j.is_null());
CHECK(not j.is_boolean()); CHECK(!j.is_boolean());
CHECK(not j.is_number()); CHECK(!j.is_number());
CHECK(not j.is_number_integer()); CHECK(!j.is_number_integer());
CHECK(not j.is_number_unsigned()); CHECK(!j.is_number_unsigned());
CHECK(not j.is_number_float()); CHECK(!j.is_number_float());
CHECK(not j.is_binary()); CHECK(!j.is_binary());
CHECK(j.is_object()); CHECK(j.is_object());
CHECK(not j.is_array()); CHECK(!j.is_array());
CHECK(not j.is_string()); CHECK(!j.is_string());
CHECK(not j.is_discarded()); CHECK(!j.is_discarded());
CHECK(not j.is_primitive()); CHECK(!j.is_primitive());
CHECK(j.is_structured()); CHECK(j.is_structured());
} }
SECTION("array") SECTION("array")
{ {
json j {"foo", 1, 1u, 42.23, false}; json j {"foo", 1, 1u, 42.23, false};
CHECK(not j.is_null()); CHECK(!j.is_null());
CHECK(not j.is_boolean()); CHECK(!j.is_boolean());
CHECK(not j.is_number()); CHECK(!j.is_number());
CHECK(not j.is_number_integer()); CHECK(!j.is_number_integer());
CHECK(not j.is_number_unsigned()); CHECK(!j.is_number_unsigned());
CHECK(not j.is_number_float()); CHECK(!j.is_number_float());
CHECK(not j.is_binary()); CHECK(!j.is_binary());
CHECK(not j.is_object()); CHECK(!j.is_object());
CHECK(j.is_array()); CHECK(j.is_array());
CHECK(not j.is_string()); CHECK(!j.is_string());
CHECK(not j.is_discarded()); CHECK(!j.is_discarded());
CHECK(not j.is_primitive()); CHECK(!j.is_primitive());
CHECK(j.is_structured()); CHECK(j.is_structured());
} }
@@ -80,144 +80,144 @@ TEST_CASE("object inspection")
{ {
json j(nullptr); json j(nullptr);
CHECK(j.is_null()); CHECK(j.is_null());
CHECK(not j.is_boolean()); CHECK(!j.is_boolean());
CHECK(not j.is_number()); CHECK(!j.is_number());
CHECK(not j.is_number_integer()); CHECK(!j.is_number_integer());
CHECK(not j.is_number_unsigned()); CHECK(!j.is_number_unsigned());
CHECK(not j.is_number_float()); CHECK(!j.is_number_float());
CHECK(not j.is_binary()); CHECK(!j.is_binary());
CHECK(not j.is_object()); CHECK(!j.is_object());
CHECK(not j.is_array()); CHECK(!j.is_array());
CHECK(not j.is_string()); CHECK(!j.is_string());
CHECK(not j.is_discarded()); CHECK(!j.is_discarded());
CHECK(j.is_primitive()); CHECK(j.is_primitive());
CHECK(not j.is_structured()); CHECK(!j.is_structured());
} }
SECTION("boolean") SECTION("boolean")
{ {
json j(true); json j(true);
CHECK(not j.is_null()); CHECK(!j.is_null());
CHECK(j.is_boolean()); CHECK(j.is_boolean());
CHECK(not j.is_number()); CHECK(!j.is_number());
CHECK(not j.is_number_integer()); CHECK(!j.is_number_integer());
CHECK(not j.is_number_unsigned()); CHECK(!j.is_number_unsigned());
CHECK(not j.is_number_float()); CHECK(!j.is_number_float());
CHECK(not j.is_binary()); CHECK(!j.is_binary());
CHECK(not j.is_object()); CHECK(!j.is_object());
CHECK(not j.is_array()); CHECK(!j.is_array());
CHECK(not j.is_string()); CHECK(!j.is_string());
CHECK(not j.is_discarded()); CHECK(!j.is_discarded());
CHECK(j.is_primitive()); CHECK(j.is_primitive());
CHECK(not j.is_structured()); CHECK(!j.is_structured());
} }
SECTION("string") SECTION("string")
{ {
json j("Hello world"); json j("Hello world");
CHECK(not j.is_null()); CHECK(!j.is_null());
CHECK(not j.is_boolean()); CHECK(!j.is_boolean());
CHECK(not j.is_number()); CHECK(!j.is_number());
CHECK(not j.is_number_integer()); CHECK(!j.is_number_integer());
CHECK(not j.is_number_unsigned()); CHECK(!j.is_number_unsigned());
CHECK(not j.is_number_float()); CHECK(!j.is_number_float());
CHECK(not j.is_binary()); CHECK(!j.is_binary());
CHECK(not j.is_object()); CHECK(!j.is_object());
CHECK(not j.is_array()); CHECK(!j.is_array());
CHECK(j.is_string()); CHECK(j.is_string());
CHECK(not j.is_discarded()); CHECK(!j.is_discarded());
CHECK(j.is_primitive()); CHECK(j.is_primitive());
CHECK(not j.is_structured()); CHECK(!j.is_structured());
} }
SECTION("number (integer)") SECTION("number (integer)")
{ {
json j(42); json j(42);
CHECK(not j.is_null()); CHECK(!j.is_null());
CHECK(not j.is_boolean()); CHECK(!j.is_boolean());
CHECK(j.is_number()); CHECK(j.is_number());
CHECK(j.is_number_integer()); CHECK(j.is_number_integer());
CHECK(not j.is_number_unsigned()); CHECK(!j.is_number_unsigned());
CHECK(not j.is_number_float()); CHECK(!j.is_number_float());
CHECK(not j.is_binary()); CHECK(!j.is_binary());
CHECK(not j.is_object()); CHECK(!j.is_object());
CHECK(not j.is_array()); CHECK(!j.is_array());
CHECK(not j.is_string()); CHECK(!j.is_string());
CHECK(not j.is_discarded()); CHECK(!j.is_discarded());
CHECK(j.is_primitive()); CHECK(j.is_primitive());
CHECK(not j.is_structured()); CHECK(!j.is_structured());
} }
SECTION("number (unsigned)") SECTION("number (unsigned)")
{ {
json j(42u); json j(42u);
CHECK(not j.is_null()); CHECK(!j.is_null());
CHECK(not j.is_boolean()); CHECK(!j.is_boolean());
CHECK(j.is_number()); CHECK(j.is_number());
CHECK(j.is_number_integer()); CHECK(j.is_number_integer());
CHECK(j.is_number_unsigned()); CHECK(j.is_number_unsigned());
CHECK(not j.is_number_float()); CHECK(!j.is_number_float());
CHECK(not j.is_binary()); CHECK(!j.is_binary());
CHECK(not j.is_object()); CHECK(!j.is_object());
CHECK(not j.is_array()); CHECK(!j.is_array());
CHECK(not j.is_string()); CHECK(!j.is_string());
CHECK(not j.is_discarded()); CHECK(!j.is_discarded());
CHECK(j.is_primitive()); CHECK(j.is_primitive());
CHECK(not j.is_structured()); CHECK(!j.is_structured());
} }
SECTION("number (floating-point)") SECTION("number (floating-point)")
{ {
json j(42.23); json j(42.23);
CHECK(not j.is_null()); CHECK(!j.is_null());
CHECK(not j.is_boolean()); CHECK(!j.is_boolean());
CHECK(j.is_number()); CHECK(j.is_number());
CHECK(not j.is_number_integer()); CHECK(!j.is_number_integer());
CHECK(not j.is_number_unsigned()); CHECK(!j.is_number_unsigned());
CHECK(j.is_number_float()); CHECK(j.is_number_float());
CHECK(not j.is_binary()); CHECK(!j.is_binary());
CHECK(not j.is_object()); CHECK(!j.is_object());
CHECK(not j.is_array()); CHECK(!j.is_array());
CHECK(not j.is_string()); CHECK(!j.is_string());
CHECK(not j.is_discarded()); CHECK(!j.is_discarded());
CHECK(j.is_primitive()); CHECK(j.is_primitive());
CHECK(not j.is_structured()); CHECK(!j.is_structured());
} }
SECTION("binary") SECTION("binary")
{ {
json j(json::value_t::binary); json j(json::value_t::binary);
CHECK(not j.is_null()); CHECK(!j.is_null());
CHECK(not j.is_boolean()); CHECK(!j.is_boolean());
CHECK(not j.is_number()); CHECK(!j.is_number());
CHECK(not j.is_number_integer()); CHECK(!j.is_number_integer());
CHECK(not j.is_number_unsigned()); CHECK(!j.is_number_unsigned());
CHECK(not j.is_number_float()); CHECK(!j.is_number_float());
CHECK(j.is_binary()); CHECK(j.is_binary());
CHECK(not j.is_object()); CHECK(!j.is_object());
CHECK(not j.is_array()); CHECK(!j.is_array());
CHECK(not j.is_string()); CHECK(!j.is_string());
CHECK(not j.is_discarded()); CHECK(!j.is_discarded());
CHECK(j.is_primitive()); CHECK(j.is_primitive());
CHECK(not j.is_structured()); CHECK(!j.is_structured());
} }
SECTION("discarded") SECTION("discarded")
{ {
json j(json::value_t::discarded); json j(json::value_t::discarded);
CHECK(not j.is_null()); CHECK(!j.is_null());
CHECK(not j.is_boolean()); CHECK(!j.is_boolean());
CHECK(not j.is_number()); CHECK(!j.is_number());
CHECK(not j.is_number_integer()); CHECK(!j.is_number_integer());
CHECK(not j.is_number_unsigned()); CHECK(!j.is_number_unsigned());
CHECK(not j.is_number_float()); CHECK(!j.is_number_float());
CHECK(not j.is_binary()); CHECK(!j.is_binary());
CHECK(not j.is_object()); CHECK(!j.is_object());
CHECK(not j.is_array()); CHECK(!j.is_array());
CHECK(not j.is_string()); CHECK(!j.is_string());
CHECK(j.is_discarded()); CHECK(j.is_discarded());
CHECK(not j.is_primitive()); CHECK(!j.is_primitive());
CHECK(not j.is_structured()); CHECK(!j.is_structured());
} }
} }
+3 -3
View File
@@ -231,12 +231,12 @@ TEST_CASE("iterators 1")
{ {
SECTION("!(begin != begin)") SECTION("!(begin != begin)")
{ {
CHECK(not(j.begin() != j.begin())); CHECK(!(j.begin() != j.begin()));
} }
SECTION("!(end != end)") SECTION("!(end != end)")
{ {
CHECK(not(j.end() != j.end())); CHECK(!(j.end() != j.end()));
} }
SECTION("begin < end") SECTION("begin < end")
@@ -286,7 +286,7 @@ TEST_CASE("iterators 1")
SECTION("!(begin == end)") SECTION("!(begin == end)")
{ {
CHECK(not(j.begin() == j.end())); CHECK(!(j.begin() == j.end()));
} }
SECTION("begin != end") SECTION("begin != end")
+64 -64
View File
@@ -56,26 +56,26 @@ TEST_CASE("iterators 2")
// comparison: equal // comparison: equal
{ {
CHECK(it1 == it1); CHECK(it1 == it1);
CHECK(not (it1 == it2)); CHECK(!(it1 == it2));
CHECK(not (it1 == it3)); CHECK(!(it1 == it3));
CHECK(not (it2 == it3)); CHECK(!(it2 == it3));
CHECK(it1_c == it1_c); CHECK(it1_c == it1_c);
CHECK(not (it1_c == it2_c)); CHECK(!(it1_c == it2_c));
CHECK(not (it1_c == it3_c)); CHECK(!(it1_c == it3_c));
CHECK(not (it2_c == it3_c)); CHECK(!(it2_c == it3_c));
} }
// comparison: not equal // comparison: not equal
{ {
// check definition // check definition
CHECK( (it1 != it1) == not(it1 == it1) ); CHECK( (it1 != it1) == !(it1 == it1) );
CHECK( (it1 != it2) == not(it1 == it2) ); CHECK( (it1 != it2) == !(it1 == it2) );
CHECK( (it1 != it3) == not(it1 == it3) ); CHECK( (it1 != it3) == !(it1 == it3) );
CHECK( (it2 != it3) == not(it2 == it3) ); CHECK( (it2 != it3) == !(it2 == it3) );
CHECK( (it1_c != it1_c) == not(it1_c == it1_c) ); CHECK( (it1_c != it1_c) == !(it1_c == it1_c) );
CHECK( (it1_c != it2_c) == not(it1_c == it2_c) ); CHECK( (it1_c != it2_c) == !(it1_c == it2_c) );
CHECK( (it1_c != it3_c) == not(it1_c == it3_c) ); CHECK( (it1_c != it3_c) == !(it1_c == it3_c) );
CHECK( (it2_c != it3_c) == not(it2_c == it3_c) ); CHECK( (it2_c != it3_c) == !(it2_c == it3_c) );
} }
// comparison: smaller // comparison: smaller
@@ -101,11 +101,11 @@ TEST_CASE("iterators 2")
} }
else else
{ {
CHECK(not (it1 < it1)); CHECK(!(it1 < it1));
CHECK(it1 < it2); CHECK(it1 < it2);
CHECK(it1 < it3); CHECK(it1 < it3);
CHECK(it2 < it3); CHECK(it2 < it3);
CHECK(not (it1_c < it1_c)); CHECK(!(it1_c < it1_c));
CHECK(it1_c < it2_c); CHECK(it1_c < it2_c);
CHECK(it1_c < it3_c); CHECK(it1_c < it3_c);
CHECK(it2_c < it3_c); CHECK(it2_c < it3_c);
@@ -136,14 +136,14 @@ TEST_CASE("iterators 2")
else else
{ {
// check definition // check definition
CHECK( (it1 <= it1) == not(it1 < it1) ); CHECK( (it1 <= it1) == !(it1 < it1) );
CHECK( (it1 <= it2) == not(it2 < it1) ); CHECK( (it1 <= it2) == !(it2 < it1) );
CHECK( (it1 <= it3) == not(it3 < it1) ); CHECK( (it1 <= it3) == !(it3 < it1) );
CHECK( (it2 <= it3) == not(it3 < it2) ); CHECK( (it2 <= it3) == !(it3 < it2) );
CHECK( (it1_c <= it1_c) == not(it1_c < it1_c) ); CHECK( (it1_c <= it1_c) == !(it1_c < it1_c) );
CHECK( (it1_c <= it2_c) == not(it2_c < it1_c) ); CHECK( (it1_c <= it2_c) == !(it2_c < it1_c) );
CHECK( (it1_c <= it3_c) == not(it3_c < it1_c) ); CHECK( (it1_c <= it3_c) == !(it3_c < it1_c) );
CHECK( (it2_c <= it3_c) == not(it3_c < it2_c) ); CHECK( (it2_c <= it3_c) == !(it3_c < it2_c) );
} }
} }
@@ -206,14 +206,14 @@ TEST_CASE("iterators 2")
else else
{ {
// check definition // check definition
CHECK( (it1 >= it1) == not(it1 < it1) ); CHECK( (it1 >= it1) == !(it1 < it1) );
CHECK( (it1 >= it2) == not(it1 < it2) ); CHECK( (it1 >= it2) == !(it1 < it2) );
CHECK( (it1 >= it3) == not(it1 < it3) ); CHECK( (it1 >= it3) == !(it1 < it3) );
CHECK( (it2 >= it3) == not(it2 < it3) ); CHECK( (it2 >= it3) == !(it2 < it3) );
CHECK( (it1_c >= it1_c) == not(it1_c < it1_c) ); CHECK( (it1_c >= it1_c) == !(it1_c < it1_c) );
CHECK( (it1_c >= it2_c) == not(it1_c < it2_c) ); CHECK( (it1_c >= it2_c) == !(it1_c < it2_c) );
CHECK( (it1_c >= it3_c) == not(it1_c < it3_c) ); CHECK( (it1_c >= it3_c) == !(it1_c < it3_c) );
CHECK( (it2_c >= it3_c) == not(it2_c < it3_c) ); CHECK( (it2_c >= it3_c) == !(it2_c < it3_c) );
} }
} }
} }
@@ -491,26 +491,26 @@ TEST_CASE("iterators 2")
// comparison: equal // comparison: equal
{ {
CHECK(it1 == it1); CHECK(it1 == it1);
CHECK(not (it1 == it2)); CHECK(!(it1 == it2));
CHECK(not (it1 == it3)); CHECK(!(it1 == it3));
CHECK(not (it2 == it3)); CHECK(!(it2 == it3));
CHECK(it1_c == it1_c); CHECK(it1_c == it1_c);
CHECK(not (it1_c == it2_c)); CHECK(!(it1_c == it2_c));
CHECK(not (it1_c == it3_c)); CHECK(!(it1_c == it3_c));
CHECK(not (it2_c == it3_c)); CHECK(!(it2_c == it3_c));
} }
// comparison: not equal // comparison: not equal
{ {
// check definition // check definition
CHECK( (it1 != it1) == not(it1 == it1) ); CHECK( (it1 != it1) == !(it1 == it1) );
CHECK( (it1 != it2) == not(it1 == it2) ); CHECK( (it1 != it2) == !(it1 == it2) );
CHECK( (it1 != it3) == not(it1 == it3) ); CHECK( (it1 != it3) == !(it1 == it3) );
CHECK( (it2 != it3) == not(it2 == it3) ); CHECK( (it2 != it3) == !(it2 == it3) );
CHECK( (it1_c != it1_c) == not(it1_c == it1_c) ); CHECK( (it1_c != it1_c) == !(it1_c == it1_c) );
CHECK( (it1_c != it2_c) == not(it1_c == it2_c) ); CHECK( (it1_c != it2_c) == !(it1_c == it2_c) );
CHECK( (it1_c != it3_c) == not(it1_c == it3_c) ); CHECK( (it1_c != it3_c) == !(it1_c == it3_c) );
CHECK( (it2_c != it3_c) == not(it2_c == it3_c) ); CHECK( (it2_c != it3_c) == !(it2_c == it3_c) );
} }
// comparison: smaller // comparison: smaller
@@ -536,11 +536,11 @@ TEST_CASE("iterators 2")
} }
else else
{ {
CHECK(not (it1 < it1)); CHECK(!(it1 < it1));
CHECK(it1 < it2); CHECK(it1 < it2);
CHECK(it1 < it3); CHECK(it1 < it3);
CHECK(it2 < it3); CHECK(it2 < it3);
CHECK(not (it1_c < it1_c)); CHECK(!(it1_c < it1_c));
CHECK(it1_c < it2_c); CHECK(it1_c < it2_c);
CHECK(it1_c < it3_c); CHECK(it1_c < it3_c);
CHECK(it2_c < it3_c); CHECK(it2_c < it3_c);
@@ -571,14 +571,14 @@ TEST_CASE("iterators 2")
else else
{ {
// check definition // check definition
CHECK( (it1 <= it1) == not(it1 < it1) ); CHECK( (it1 <= it1) == !(it1 < it1) );
CHECK( (it1 <= it2) == not(it2 < it1) ); CHECK( (it1 <= it2) == !(it2 < it1) );
CHECK( (it1 <= it3) == not(it3 < it1) ); CHECK( (it1 <= it3) == !(it3 < it1) );
CHECK( (it2 <= it3) == not(it3 < it2) ); CHECK( (it2 <= it3) == !(it3 < it2) );
CHECK( (it1_c <= it1_c) == not(it1_c < it1_c) ); CHECK( (it1_c <= it1_c) == !(it1_c < it1_c) );
CHECK( (it1_c <= it2_c) == not(it2_c < it1_c) ); CHECK( (it1_c <= it2_c) == !(it2_c < it1_c) );
CHECK( (it1_c <= it3_c) == not(it3_c < it1_c) ); CHECK( (it1_c <= it3_c) == !(it3_c < it1_c) );
CHECK( (it2_c <= it3_c) == not(it3_c < it2_c) ); CHECK( (it2_c <= it3_c) == !(it3_c < it2_c) );
} }
} }
@@ -641,14 +641,14 @@ TEST_CASE("iterators 2")
else else
{ {
// check definition // check definition
CHECK( (it1 >= it1) == not(it1 < it1) ); CHECK( (it1 >= it1) == !(it1 < it1) );
CHECK( (it1 >= it2) == not(it1 < it2) ); CHECK( (it1 >= it2) == !(it1 < it2) );
CHECK( (it1 >= it3) == not(it1 < it3) ); CHECK( (it1 >= it3) == !(it1 < it3) );
CHECK( (it2 >= it3) == not(it2 < it3) ); CHECK( (it2 >= it3) == !(it2 < it3) );
CHECK( (it1_c >= it1_c) == not(it1_c < it1_c) ); CHECK( (it1_c >= it1_c) == !(it1_c < it1_c) );
CHECK( (it1_c >= it2_c) == not(it1_c < it2_c) ); CHECK( (it1_c >= it2_c) == !(it1_c < it2_c) );
CHECK( (it1_c >= it3_c) == not(it1_c < it3_c) ); CHECK( (it1_c >= it3_c) == !(it1_c < it3_c) );
CHECK( (it2_c >= it3_c) == not(it2_c < it3_c) ); CHECK( (it2_c >= it3_c) == !(it2_c < it3_c) );
} }
} }
} }
+46 -29
View File
@@ -101,10 +101,10 @@ TEST_CASE("JSON pointers")
CHECK(j["/foo/1"_json_pointer] == j["foo"][1]); CHECK(j["/foo/1"_json_pointer] == j["foo"][1]);
CHECK(j.contains(json::json_pointer("/foo/0"))); CHECK(j.contains(json::json_pointer("/foo/0")));
CHECK(j.contains(json::json_pointer("/foo/1"))); CHECK(j.contains(json::json_pointer("/foo/1")));
CHECK(not j.contains(json::json_pointer("/foo/3"))); CHECK(!j.contains(json::json_pointer("/foo/3")));
CHECK(not j.contains(json::json_pointer("/foo/+"))); CHECK(!j.contains(json::json_pointer("/foo/+")));
CHECK(not j.contains(json::json_pointer("/foo/1+2"))); CHECK(!j.contains(json::json_pointer("/foo/1+2")));
CHECK(not j.contains(json::json_pointer("/foo/-"))); CHECK(!j.contains(json::json_pointer("/foo/-")));
// checked array access // checked array access
CHECK(j.at(json::json_pointer("/foo/0")) == j["foo"][0]); CHECK(j.at(json::json_pointer("/foo/0")) == j["foo"][0]);
@@ -147,19 +147,19 @@ TEST_CASE("JSON pointers")
// unescaped access // unescaped access
// access to nonexisting values yield object creation // access to nonexisting values yield object creation
CHECK(not j.contains(json::json_pointer("/a/b"))); CHECK(!j.contains(json::json_pointer("/a/b")));
CHECK_NOTHROW(j[json::json_pointer("/a/b")] = 42); CHECK_NOTHROW(j[json::json_pointer("/a/b")] = 42);
CHECK(j.contains(json::json_pointer("/a/b"))); CHECK(j.contains(json::json_pointer("/a/b")));
CHECK(j["a"]["b"] == json(42)); CHECK(j["a"]["b"] == json(42));
CHECK(not j.contains(json::json_pointer("/a/c/1"))); CHECK(!j.contains(json::json_pointer("/a/c/1")));
CHECK_NOTHROW(j[json::json_pointer("/a/c/1")] = 42); CHECK_NOTHROW(j[json::json_pointer("/a/c/1")] = 42);
CHECK(j["a"]["c"] == json({nullptr, 42})); CHECK(j["a"]["c"] == json({nullptr, 42}));
CHECK(j.contains(json::json_pointer("/a/c/1"))); CHECK(j.contains(json::json_pointer("/a/c/1")));
CHECK(not j.contains(json::json_pointer("/a/d/-"))); CHECK(!j.contains(json::json_pointer("/a/d/-")));
CHECK_NOTHROW(j[json::json_pointer("/a/d/-")] = 42); CHECK_NOTHROW(j[json::json_pointer("/a/d/-")] = 42);
CHECK(not j.contains(json::json_pointer("/a/d/-"))); CHECK(!j.contains(json::json_pointer("/a/d/-")));
CHECK(j["a"]["d"] == json::array({42})); CHECK(j["a"]["d"] == json::array({42}));
// "/a/b" works for JSON {"a": {"b": 42}} // "/a/b" works for JSON {"a": {"b": 42}}
CHECK(json({{"a", {{"b", 42}}}})[json::json_pointer("/a/b")] == json(42)); CHECK(json({{"a", {{"b", 42}}}})[json::json_pointer("/a/b")] == json(42));
@@ -172,7 +172,7 @@ TEST_CASE("JSON pointers")
CHECK_THROWS_AS(j_primitive.at("/foo"_json_pointer), json::out_of_range&); CHECK_THROWS_AS(j_primitive.at("/foo"_json_pointer), json::out_of_range&);
CHECK_THROWS_WITH(j_primitive.at("/foo"_json_pointer), CHECK_THROWS_WITH(j_primitive.at("/foo"_json_pointer),
"[json.exception.out_of_range.404] unresolved reference token 'foo'"); "[json.exception.out_of_range.404] unresolved reference token 'foo'");
CHECK(not j_primitive.contains(json::json_pointer("/foo"))); CHECK(!j_primitive.contains(json::json_pointer("/foo")));
} }
SECTION("const access") SECTION("const access")
@@ -272,7 +272,7 @@ TEST_CASE("JSON pointers")
CHECK(j.contains("/foo"_json_pointer)); CHECK(j.contains("/foo"_json_pointer));
CHECK(j.contains("/foo/0"_json_pointer)); CHECK(j.contains("/foo/0"_json_pointer));
CHECK(j.contains("/foo/1"_json_pointer)); CHECK(j.contains("/foo/1"_json_pointer));
CHECK(not j.contains("/foo/-"_json_pointer)); CHECK(!j.contains("/foo/-"_json_pointer));
} }
} }
@@ -314,10 +314,10 @@ TEST_CASE("JSON pointers")
CHECK_THROWS_WITH(j_const.at("/01"_json_pointer), CHECK_THROWS_WITH(j_const.at("/01"_json_pointer),
"[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'"); "[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'");
CHECK(not j.contains("/01"_json_pointer)); CHECK(!j.contains("/01"_json_pointer));
CHECK(not j.contains("/01"_json_pointer)); CHECK(!j.contains("/01"_json_pointer));
CHECK(not j_const.contains("/01"_json_pointer)); CHECK(!j_const.contains("/01"_json_pointer));
CHECK(not j_const.contains("/01"_json_pointer)); CHECK(!j_const.contains("/01"_json_pointer));
// error with incorrect numbers // error with incorrect numbers
CHECK_THROWS_AS(j["/one"_json_pointer] = 1, json::parse_error&); CHECK_THROWS_AS(j["/one"_json_pointer] = 1, json::parse_error&);
@@ -348,12 +348,29 @@ TEST_CASE("JSON pointers")
CHECK_THROWS_WITH(j_const["/1+1"_json_pointer] == 1, CHECK_THROWS_WITH(j_const["/1+1"_json_pointer] == 1,
"[json.exception.out_of_range.404] unresolved reference token '1+1'"); "[json.exception.out_of_range.404] unresolved reference token '1+1'");
CHECK_THROWS_AS(j["/111111111111111111111111"_json_pointer] = 1, json::out_of_range&); {
CHECK_THROWS_WITH(j["/111111111111111111111111"_json_pointer] = 1, auto too_large_index = std::to_string((std::numeric_limits<unsigned long long>::max)()) + "1";
"[json.exception.out_of_range.404] unresolved reference token '111111111111111111111111'"); json::json_pointer jp(std::string("/") + too_large_index);
CHECK_THROWS_AS(j_const["/111111111111111111111111"_json_pointer] == 1, json::out_of_range&); std::string throw_msg = std::string("[json.exception.out_of_range.404] unresolved reference token '") + too_large_index + "'";
CHECK_THROWS_WITH(j_const["/111111111111111111111111"_json_pointer] == 1,
"[json.exception.out_of_range.404] unresolved reference token '111111111111111111111111'"); CHECK_THROWS_AS(j[jp] = 1, json::out_of_range&);
CHECK_THROWS_WITH(j[jp] = 1, throw_msg.c_str());
CHECK_THROWS_AS(j_const[jp] == 1, json::out_of_range&);
CHECK_THROWS_WITH(j_const[jp] == 1, throw_msg.c_str());
}
if (sizeof(typename json::size_type) < sizeof(unsigned long long))
{
auto size_type_max_uul = static_cast<unsigned long long>((std::numeric_limits<json::size_type>::max)());
auto too_large_index = std::to_string(size_type_max_uul);
json::json_pointer jp(std::string("/") + too_large_index);
std::string throw_msg = std::string("[json.exception.out_of_range.410] array index ") + too_large_index + " exceeds size_type";
CHECK_THROWS_AS(j[jp] = 1, json::out_of_range&);
CHECK_THROWS_WITH(j[jp] = 1, throw_msg.c_str());
CHECK_THROWS_AS(j_const[jp] == 1, json::out_of_range&);
CHECK_THROWS_WITH(j_const[jp] == 1, throw_msg.c_str());
}
CHECK_THROWS_AS(j.at("/one"_json_pointer) = 1, json::parse_error&); CHECK_THROWS_AS(j.at("/one"_json_pointer) = 1, json::parse_error&);
CHECK_THROWS_WITH(j.at("/one"_json_pointer) = 1, CHECK_THROWS_WITH(j.at("/one"_json_pointer) = 1,
@@ -362,10 +379,10 @@ TEST_CASE("JSON pointers")
CHECK_THROWS_WITH(j_const.at("/one"_json_pointer) == 1, CHECK_THROWS_WITH(j_const.at("/one"_json_pointer) == 1,
"[json.exception.parse_error.109] parse error: array index 'one' is not a number"); "[json.exception.parse_error.109] parse error: array index 'one' is not a number");
CHECK(not j.contains("/one"_json_pointer)); CHECK(!j.contains("/one"_json_pointer));
CHECK(not j.contains("/one"_json_pointer)); CHECK(!j.contains("/one"_json_pointer));
CHECK(not j_const.contains("/one"_json_pointer)); CHECK(!j_const.contains("/one"_json_pointer));
CHECK(not j_const.contains("/one"_json_pointer)); CHECK(!j_const.contains("/one"_json_pointer));
CHECK_THROWS_AS(json({{"/list/0", 1}, {"/list/1", 2}, {"/list/three", 3}}).unflatten(), json::parse_error&); CHECK_THROWS_AS(json({{"/list/0", 1}, {"/list/1", 2}, {"/list/three", 3}}).unflatten(), json::parse_error&);
CHECK_THROWS_WITH(json({{"/list/0", 1}, {"/list/1", 2}, {"/list/three", 3}}).unflatten(), CHECK_THROWS_WITH(json({{"/list/0", 1}, {"/list/1", 2}, {"/list/three", 3}}).unflatten(),
@@ -379,7 +396,7 @@ TEST_CASE("JSON pointers")
CHECK_THROWS_AS(j_const["/-"_json_pointer], json::out_of_range&); CHECK_THROWS_AS(j_const["/-"_json_pointer], json::out_of_range&);
CHECK_THROWS_WITH(j_const["/-"_json_pointer], CHECK_THROWS_WITH(j_const["/-"_json_pointer],
"[json.exception.out_of_range.402] array index '-' (3) is out of range"); "[json.exception.out_of_range.402] array index '-' (3) is out of range");
CHECK(not j_const.contains("/-"_json_pointer)); CHECK(!j_const.contains("/-"_json_pointer));
// error when using "-" with at // error when using "-" with at
CHECK_THROWS_AS(j.at("/-"_json_pointer), json::out_of_range&); CHECK_THROWS_AS(j.at("/-"_json_pointer), json::out_of_range&);
@@ -388,7 +405,7 @@ TEST_CASE("JSON pointers")
CHECK_THROWS_AS(j_const.at("/-"_json_pointer), json::out_of_range&); CHECK_THROWS_AS(j_const.at("/-"_json_pointer), json::out_of_range&);
CHECK_THROWS_WITH(j_const.at("/-"_json_pointer), CHECK_THROWS_WITH(j_const.at("/-"_json_pointer),
"[json.exception.out_of_range.402] array index '-' (3) is out of range"); "[json.exception.out_of_range.402] array index '-' (3) is out of range");
CHECK(not j_const.contains("/-"_json_pointer)); CHECK(!j_const.contains("/-"_json_pointer));
} }
SECTION("const access") SECTION("const access")
@@ -404,13 +421,13 @@ TEST_CASE("JSON pointers")
CHECK_THROWS_AS(j.at("/3"_json_pointer), json::out_of_range&); CHECK_THROWS_AS(j.at("/3"_json_pointer), json::out_of_range&);
CHECK_THROWS_WITH(j.at("/3"_json_pointer), CHECK_THROWS_WITH(j.at("/3"_json_pointer),
"[json.exception.out_of_range.401] array index 3 is out of range"); "[json.exception.out_of_range.401] array index 3 is out of range");
CHECK(not j.contains("/3"_json_pointer)); CHECK(!j.contains("/3"_json_pointer));
// assign to nonexisting index (with gap) // assign to nonexisting index (with gap)
CHECK_THROWS_AS(j.at("/5"_json_pointer), json::out_of_range&); CHECK_THROWS_AS(j.at("/5"_json_pointer), json::out_of_range&);
CHECK_THROWS_WITH(j.at("/5"_json_pointer), CHECK_THROWS_WITH(j.at("/5"_json_pointer),
"[json.exception.out_of_range.401] array index 5 is out of range"); "[json.exception.out_of_range.401] array index 5 is out of range");
CHECK(not j.contains("/5"_json_pointer)); CHECK(!j.contains("/5"_json_pointer));
// assign to "-" // assign to "-"
CHECK_THROWS_AS(j["/-"_json_pointer], json::out_of_range&); CHECK_THROWS_AS(j["/-"_json_pointer], json::out_of_range&);
@@ -419,7 +436,7 @@ TEST_CASE("JSON pointers")
CHECK_THROWS_AS(j.at("/-"_json_pointer), json::out_of_range&); CHECK_THROWS_AS(j.at("/-"_json_pointer), json::out_of_range&);
CHECK_THROWS_WITH(j.at("/-"_json_pointer), CHECK_THROWS_WITH(j.at("/-"_json_pointer),
"[json.exception.out_of_range.402] array index '-' (3) is out of range"); "[json.exception.out_of_range.402] array index '-' (3) is out of range");
CHECK(not j.contains("/-"_json_pointer)); CHECK(!j.contains("/-"_json_pointer));
} }
} }
+4 -3
View File
@@ -114,7 +114,7 @@ TEST_CASE("modifiers")
json k = j; json k = j;
j.clear(); j.clear();
CHECK(not j.empty()); CHECK(!j.empty());
CHECK(j == json(json::value_t::binary)); CHECK(j == json(json::value_t::binary));
CHECK(j == json(k.type())); CHECK(j == json(k.type()));
} }
@@ -125,7 +125,7 @@ TEST_CASE("modifiers")
json k = j; json k = j;
j.clear(); j.clear();
CHECK(not j.empty()); CHECK(!j.empty());
CHECK(j == json(json::value_t::binary)); CHECK(j == json(json::value_t::binary));
CHECK(j == json(k.type())); CHECK(j == json(k.type()));
} }
@@ -878,7 +878,8 @@ TEST_CASE("modifiers")
json j("hello world"); json j("hello world");
json k(42.23); json k(42.23);
std::swap(j, k); using std::swap;
swap(j, k);
CHECK(j == json(42.23)); CHECK(j == json(42.23));
CHECK(k == json("hello world")); CHECK(k == json("hello world"));
+37 -3
View File
@@ -783,6 +783,40 @@ TEST_CASE("MessagePack")
CHECK(json::from_msgpack(result) == v); CHECK(json::from_msgpack(result) == v);
CHECK(json::from_msgpack(result, true, false) == j); CHECK(json::from_msgpack(result, true, false) == j);
} }
SECTION("1.0")
{
double v = 1.0;
json j = v;
std::vector<uint8_t> expected =
{
0xca, 0x3f, 0x80, 0x00, 0x00
};
const auto result = json::to_msgpack(j);
CHECK(result == expected);
// roundtrip
CHECK(json::from_msgpack(result) == j);
CHECK(json::from_msgpack(result) == v);
CHECK(json::from_msgpack(result, true, false) == j);
}
SECTION("128.128")
{
double v = 128.1280059814453125;
json j = v;
std::vector<uint8_t> expected =
{
0xca, 0x43, 0x00, 0x20, 0xc5
};
const auto result = json::to_msgpack(j);
CHECK(result == expected);
// roundtrip
CHECK(json::from_msgpack(result) == j);
CHECK(json::from_msgpack(result) == v);
CHECK(json::from_msgpack(result, true, false) == j);
}
} }
} }
@@ -1544,21 +1578,21 @@ TEST_CASE("MessagePack")
{ {
std::vector<uint8_t> v = {0x93, 0x01, 0x02, 0x03}; std::vector<uint8_t> v = {0x93, 0x01, 0x02, 0x03};
SaxCountdown scp(0); SaxCountdown scp(0);
CHECK(not json::sax_parse(v, &scp, json::input_format_t::msgpack)); CHECK(!json::sax_parse(v, &scp, json::input_format_t::msgpack));
} }
SECTION("start_object(len)") SECTION("start_object(len)")
{ {
std::vector<uint8_t> v = {0x81, 0xa3, 0x66, 0x6F, 0x6F, 0xc2}; std::vector<uint8_t> v = {0x81, 0xa3, 0x66, 0x6F, 0x6F, 0xc2};
SaxCountdown scp(0); SaxCountdown scp(0);
CHECK(not json::sax_parse(v, &scp, json::input_format_t::msgpack)); CHECK(!json::sax_parse(v, &scp, json::input_format_t::msgpack));
} }
SECTION("key()") SECTION("key()")
{ {
std::vector<uint8_t> v = {0x81, 0xa3, 0x66, 0x6F, 0x6F, 0xc2}; std::vector<uint8_t> v = {0x81, 0xa3, 0x66, 0x6F, 0x6F, 0xc2};
SaxCountdown scp(1); SaxCountdown scp(1);
CHECK(not json::sax_parse(v, &scp, json::input_format_t::msgpack)); CHECK(!json::sax_parse(v, &scp, json::input_format_t::msgpack));
} }
} }
} }
+2 -2
View File
@@ -59,12 +59,12 @@ static_assert(noexcept(nlohmann::to_json(*j, 2.5)), "");
static_assert(noexcept(nlohmann::to_json(*j, true)), ""); static_assert(noexcept(nlohmann::to_json(*j, true)), "");
static_assert(noexcept(nlohmann::to_json(*j, test{})), ""); static_assert(noexcept(nlohmann::to_json(*j, test{})), "");
static_assert(noexcept(nlohmann::to_json(*j, pod{})), ""); static_assert(noexcept(nlohmann::to_json(*j, pod{})), "");
static_assert(not noexcept(nlohmann::to_json(*j, pod_bis{})), ""); static_assert(!noexcept(nlohmann::to_json(*j, pod_bis{})), "");
static_assert(noexcept(json(2)), ""); static_assert(noexcept(json(2)), "");
static_assert(noexcept(json(test{})), ""); static_assert(noexcept(json(test{})), "");
static_assert(noexcept(json(pod{})), ""); static_assert(noexcept(json(pod{})), "");
static_assert(noexcept(j->get<pod>()), ""); static_assert(noexcept(j->get<pod>()), "");
static_assert(not noexcept(j->get<pod_bis>()), ""); static_assert(!noexcept(j->get<pod_bis>()), "");
static_assert(noexcept(json(pod{})), ""); static_assert(noexcept(json(pod{})), "");
} }
+79
View File
@@ -0,0 +1,79 @@
/*
__ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 3.8.0
|_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
SPDX-License-Identifier: MIT
Copyright (c) 2013-2019 Niels Lohmann <http://nlohmann.me>.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "doctest_compatibility.h"
#include <nlohmann/json.hpp>
using nlohmann::json;
using nlohmann::ordered_json;
TEST_CASE("ordered_json")
{
json j;
ordered_json oj;
j["element3"] = 3;
j["element1"] = 1;
j["element2"] = 2;
oj["element3"] = 3;
oj["element1"] = 1;
oj["element2"] = 2;
CHECK(j.dump() == "{\"element1\":1,\"element2\":2,\"element3\":3}");
CHECK(oj.dump() == "{\"element3\":3,\"element1\":1,\"element2\":2}");
CHECK(j == json(oj));
CHECK(ordered_json(json(oj)) == ordered_json(j));
j.erase("element1");
oj.erase("element1");
CHECK(j.dump() == "{\"element2\":2,\"element3\":3}");
CHECK(oj.dump() == "{\"element3\":3,\"element2\":2}");
// remove again and nothing changes
j.erase("element1");
oj.erase("element1");
CHECK(j.dump() == "{\"element2\":2,\"element3\":3}");
CHECK(oj.dump() == "{\"element3\":3,\"element2\":2}");
// There are no dup keys cause constructor calls emplace...
json multi {{"z", 1}, {"m", 2}, {"m", 3}, {"y", 4}, {"m", 5}};
CHECK(multi.size() == 3);
CHECK(multi.dump() == "{\"m\":2,\"y\":4,\"z\":1}");
ordered_json multi_ordered {{"z", 1}, {"m", 2}, {"m", 3}, {"y", 4}, {"m", 5}};
CHECK(multi_ordered.size() == 3);
CHECK(multi_ordered.dump() == "{\"z\":1,\"m\":2,\"y\":4}");
CHECK(multi_ordered.erase("m") == 1);
CHECK(multi_ordered.dump() == "{\"z\":1,\"y\":4}");
}
+28 -14
View File
@@ -254,12 +254,12 @@ TEST_CASE("regression tests")
json j1 = INFINITY; json j1 = INFINITY;
CHECK(j1.is_number_float()); CHECK(j1.is_number_float());
json::number_float_t f1 = j1; json::number_float_t f1 = j1;
CHECK(not std::isfinite(f1)); CHECK(!std::isfinite(f1));
json j2 = json::number_float_t(INFINITY); json j2 = json::number_float_t(INFINITY);
CHECK(j2.is_number_float()); CHECK(j2.is_number_float());
json::number_float_t f2 = j2; json::number_float_t f2 = j2;
CHECK(not std::isfinite(f2)); CHECK(!std::isfinite(f2));
} }
} }
@@ -1350,10 +1350,10 @@ TEST_CASE("regression tests")
CHECK(j["a"] > 3); CHECK(j["a"] > 3);
CHECK(not(j["a"] <= 4)); CHECK(!(j["a"] <= 4));
CHECK(not(j["a"] < 4)); CHECK(!(j["a"] < 4));
CHECK(not(j["a"] >= 6)); CHECK(!(j["a"] >= 6));
CHECK(not(j["a"] > 6)); CHECK(!(j["a"] > 6));
// scalar op json // scalar op json
CHECK(5 == j["a"]); CHECK(5 == j["a"]);
@@ -1364,10 +1364,10 @@ TEST_CASE("regression tests")
CHECK(3 <= j["a"]); CHECK(3 <= j["a"]);
CHECK(3 < j["a"]); CHECK(3 < j["a"]);
CHECK(not(4 >= j["a"])); CHECK(!(4 >= j["a"]));
CHECK(not(4 > j["a"])); CHECK(!(4 > j["a"]));
CHECK(not(6 <= j["a"])); CHECK(!(6 <= j["a"]));
CHECK(not(6 < j["a"])); CHECK(!(6 < j["a"]));
} }
SECTION("issue #575 - heap-buffer-overflow (OSS-Fuzz 1400)") SECTION("issue #575 - heap-buffer-overflow (OSS-Fuzz 1400)")
@@ -1608,7 +1608,7 @@ TEST_CASE("regression tests")
json::parser_callback_t cb = [](int /*depth*/, json::parse_event_t event, json & parsed) json::parser_callback_t cb = [](int /*depth*/, json::parse_event_t event, json & parsed)
{ {
// skip object elements with key "Thumbnail" // skip object elements with key "Thumbnail"
if (event == json::parse_event_t::key and parsed == json("Thumbnail")) if (event == json::parse_event_t::key && parsed == json("Thumbnail"))
{ {
return false; return false;
} }
@@ -1680,7 +1680,7 @@ TEST_CASE("regression tests")
json::parser_callback_t cb = [&](int, json::parse_event_t event, json & parsed) json::parser_callback_t cb = [&](int, json::parse_event_t event, json & parsed)
{ {
// skip uninteresting events // skip uninteresting events
if (event == json::parse_event_t::value and !parsed.is_primitive()) if (event == json::parse_event_t::value && !parsed.is_primitive())
{ {
return false; return false;
} }
@@ -1760,7 +1760,7 @@ TEST_CASE("regression tests")
SECTION("issue #1292 - Serializing std::variant causes stack overflow") SECTION("issue #1292 - Serializing std::variant causes stack overflow")
{ {
static_assert( static_assert(
not std::is_constructible<json, std::variant<int, float>>::value, ""); !std::is_constructible<json, std::variant<int, float>>::value, "");
} }
#endif #endif
@@ -1945,9 +1945,18 @@ TEST_CASE("regression tests")
) )
); );
} }
SECTION("PR #2181 - regression bug with lvalue")
{
// see https://github.com/nlohmann/json/pull/2181#issuecomment-653326060
json j{{"x", "test"}};
std::string defval = "default value";
auto val = j.value("x", defval);
auto val2 = j.value("y", defval);
}
} }
#if not defined(JSON_NOEXCEPTION) #if !defined(JSON_NOEXCEPTION)
TEST_CASE("regression tests, exceptions dependent") TEST_CASE("regression tests, exceptions dependent")
{ {
SECTION("issue #1340 - eof not set on exhausted input stream") SECTION("issue #1340 - eof not set on exhausted input stream")
@@ -1965,9 +1974,14 @@ TEST_CASE("regression tests, exceptions dependent")
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
// for #1642 // for #1642
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
// the code below fails with Clang on Windows, so we need to exclude it there
#if defined(__clang__) && (defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__))
#else
template <typename T> class array {}; template <typename T> class array {};
template <typename T> class object {}; template <typename T> class object {};
template <typename T> class string {}; template <typename T> class string {};
template <typename T> class number_integer {}; template <typename T> class number_integer {};
template <typename T> class number_unsigned {}; template <typename T> class number_unsigned {};
template <typename T> class number_float {}; template <typename T> class number_float {};
#endif
+3 -3
View File
@@ -1235,7 +1235,7 @@ TEST_CASE("nst's JSONTestSuite (2)")
json _; json _;
CHECK_THROWS_AS(_ = json::parse(f), json::parse_error&); CHECK_THROWS_AS(_ = json::parse(f), json::parse_error&);
std::ifstream f2(filename); std::ifstream f2(filename);
CHECK(not json::accept(f2)); CHECK(!json::accept(f2));
} }
} }
@@ -1250,7 +1250,7 @@ TEST_CASE("nst's JSONTestSuite (2)")
{ {
CAPTURE(filename) CAPTURE(filename)
std::ifstream f(filename); std::ifstream f(filename);
CHECK(not json::accept(f)); CHECK(!json::accept(f));
} }
} }
@@ -1352,7 +1352,7 @@ TEST_CASE("nst's JSONTestSuite (2)")
json _; json _;
CHECK_THROWS_AS(_ = json::parse(f), json::exception&); // could be parse_error or out_of_range CHECK_THROWS_AS(_ = json::parse(f), json::exception&); // could be parse_error or out_of_range
std::ifstream f2(filename); std::ifstream f2(filename);
CHECK(not json::accept(f2)); CHECK(!json::accept(f2));
} }
} }
} }
+7 -7
View File
@@ -1586,42 +1586,42 @@ TEST_CASE("UBJSON")
{ {
std::vector<uint8_t> v = {'[', 'T', 'F', ']'}; std::vector<uint8_t> v = {'[', 'T', 'F', ']'};
SaxCountdown scp(0); SaxCountdown scp(0);
CHECK(not json::sax_parse(v, &scp, json::input_format_t::ubjson)); CHECK(!json::sax_parse(v, &scp, json::input_format_t::ubjson));
} }
SECTION("start_object()") SECTION("start_object()")
{ {
std::vector<uint8_t> v = {'{', 'i', 3, 'f', 'o', 'o', 'F', '}'}; std::vector<uint8_t> v = {'{', 'i', 3, 'f', 'o', 'o', 'F', '}'};
SaxCountdown scp(0); SaxCountdown scp(0);
CHECK(not json::sax_parse(v, &scp, json::input_format_t::ubjson)); CHECK(!json::sax_parse(v, &scp, json::input_format_t::ubjson));
} }
SECTION("key() in object") SECTION("key() in object")
{ {
std::vector<uint8_t> v = {'{', 'i', 3, 'f', 'o', 'o', 'F', '}'}; std::vector<uint8_t> v = {'{', 'i', 3, 'f', 'o', 'o', 'F', '}'};
SaxCountdown scp(1); SaxCountdown scp(1);
CHECK(not json::sax_parse(v, &scp, json::input_format_t::ubjson)); CHECK(!json::sax_parse(v, &scp, json::input_format_t::ubjson));
} }
SECTION("start_array(len)") SECTION("start_array(len)")
{ {
std::vector<uint8_t> v = {'[', '#', 'i', '2', 'T', 'F'}; std::vector<uint8_t> v = {'[', '#', 'i', '2', 'T', 'F'};
SaxCountdown scp(0); SaxCountdown scp(0);
CHECK(not json::sax_parse(v, &scp, json::input_format_t::ubjson)); CHECK(!json::sax_parse(v, &scp, json::input_format_t::ubjson));
} }
SECTION("start_object(len)") SECTION("start_object(len)")
{ {
std::vector<uint8_t> v = {'{', '#', 'i', '1', 3, 'f', 'o', 'o', 'F'}; std::vector<uint8_t> v = {'{', '#', 'i', '1', 3, 'f', 'o', 'o', 'F'};
SaxCountdown scp(0); SaxCountdown scp(0);
CHECK(not json::sax_parse(v, &scp, json::input_format_t::ubjson)); CHECK(!json::sax_parse(v, &scp, json::input_format_t::ubjson));
} }
SECTION("key() in object with length") SECTION("key() in object with length")
{ {
std::vector<uint8_t> v = {'{', 'i', 3, 'f', 'o', 'o', 'F', '}'}; std::vector<uint8_t> v = {'{', 'i', 3, 'f', 'o', 'o', 'F', '}'};
SaxCountdown scp(1); SaxCountdown scp(1);
CHECK(not json::sax_parse(v, &scp, json::input_format_t::ubjson)); CHECK(!json::sax_parse(v, &scp, json::input_format_t::ubjson));
} }
} }
@@ -2363,7 +2363,7 @@ TEST_CASE("Universal Binary JSON Specification Examples 1")
} }
} }
#if not defined(JSON_NOEXCEPTION) #if !defined(JSON_NOEXCEPTION)
TEST_CASE("all UBJSON first bytes") TEST_CASE("all UBJSON first bytes")
{ {
// these bytes will fail immediately with exception parse_error.112 // these bytes will fail immediately with exception parse_error.112
+6 -6
View File
@@ -551,7 +551,7 @@ struct pod_serializer
template < template <
typename BasicJsonType, typename U = T, typename BasicJsonType, typename U = T,
typename std::enable_if < typename std::enable_if <
not(std::is_pod<U>::value and std::is_class<U>::value), int >::type = 0 > !(std::is_pod<U>::value && std::is_class<U>::value), int >::type = 0 >
static void from_json(const BasicJsonType& j, U& t) static void from_json(const BasicJsonType& j, U& t)
{ {
using nlohmann::from_json; using nlohmann::from_json;
@@ -561,7 +561,7 @@ struct pod_serializer
// special behaviour for pods // special behaviour for pods
template < typename BasicJsonType, typename U = T, template < typename BasicJsonType, typename U = T,
typename std::enable_if < typename std::enable_if <
std::is_pod<U>::value and std::is_class<U>::value, int>::type = 0> std::is_pod<U>::value && std::is_class<U>::value, int >::type = 0 >
static void from_json(const BasicJsonType& j, U& t) static void from_json(const BasicJsonType& j, U& t)
{ {
std::uint64_t value; std::uint64_t value;
@@ -587,7 +587,7 @@ struct pod_serializer
template < template <
typename BasicJsonType, typename U = T, typename BasicJsonType, typename U = T,
typename std::enable_if < typename std::enable_if <
not(std::is_pod<U>::value and std::is_class<U>::value), int >::type = 0 > !(std::is_pod<U>::value && std::is_class<U>::value), int >::type = 0 >
static void to_json(BasicJsonType& j, const T& t) static void to_json(BasicJsonType& j, const T& t)
{ {
using nlohmann::to_json; using nlohmann::to_json;
@@ -596,7 +596,7 @@ struct pod_serializer
template < typename BasicJsonType, typename U = T, template < typename BasicJsonType, typename U = T,
typename std::enable_if < typename std::enable_if <
std::is_pod<U>::value and std::is_class<U>::value, int>::type = 0> std::is_pod<U>::value && std::is_class<U>::value, int >::type = 0 >
static void to_json(BasicJsonType& j, const T& t) noexcept static void to_json(BasicJsonType& j, const T& t) noexcept
{ {
auto bytes = static_cast< const unsigned char*>(static_cast<const void*>(&t)); auto bytes = static_cast< const unsigned char*>(static_cast<const void*>(&t));
@@ -805,7 +805,7 @@ struct is_constructible_patched<T, decltype(void(json(std::declval<T>())))> : st
TEST_CASE("an incomplete type does not trigger a compiler error in non-evaluated context" * doctest::test_suite("udt")) TEST_CASE("an incomplete type does not trigger a compiler error in non-evaluated context" * doctest::test_suite("udt"))
{ {
static_assert(not is_constructible_patched<json, incomplete>::value, ""); static_assert(!is_constructible_patched<json, incomplete>::value, "");
} }
namespace namespace
@@ -839,5 +839,5 @@ TEST_CASE("Issue #924")
TEST_CASE("Issue #1237") TEST_CASE("Issue #1237")
{ {
struct non_convertible_type {}; struct non_convertible_type {};
static_assert(not std::is_convertible<json, non_convertible_type>::value, ""); static_assert(!std::is_convertible<json, non_convertible_type>::value, "");
} }
+130
View File
@@ -0,0 +1,130 @@
/*
__ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 3.8.0
|_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
SPDX-License-Identifier: MIT
Copyright (c) 2013-2019 Niels Lohmann <http://nlohmann.me>.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "doctest_compatibility.h"
#include <nlohmann/json.hpp>
using nlohmann::json;
namespace persons
{
class person_with_private_data
{
private:
std::string name = "";
int age = 0;
json metadata = nullptr;
public:
bool operator==(const person_with_private_data& rhs) const
{
return name == rhs.name && age == rhs.age && metadata == rhs.metadata;
}
person_with_private_data() = default;
person_with_private_data(std::string name_, int age_, json metadata_)
: name(std::move(name_))
, age(age_)
, metadata(std::move(metadata_))
{}
NLOHMANN_DEFINE_TYPE_INTRUSIVE(person_with_private_data, age, name, metadata)
};
class person_without_private_data_1
{
public:
std::string name = "";
int age = 0;
json metadata = nullptr;
bool operator==(const person_without_private_data_1& rhs) const
{
return name == rhs.name && age == rhs.age && metadata == rhs.metadata;
}
person_without_private_data_1() = default;
person_without_private_data_1(std::string name_, int age_, json metadata_)
: name(std::move(name_))
, age(age_)
, metadata(std::move(metadata_))
{}
NLOHMANN_DEFINE_TYPE_INTRUSIVE(person_without_private_data_1, age, name, metadata)
};
class person_without_private_data_2
{
public:
std::string name = "";
int age = 0;
json metadata = nullptr;
bool operator==(const person_without_private_data_2& rhs) const
{
return name == rhs.name && age == rhs.age && metadata == rhs.metadata;
}
person_without_private_data_2() = default;
person_without_private_data_2(std::string name_, int age_, json metadata_)
: name(std::move(name_))
, age(age_)
, metadata(std::move(metadata_))
{}
};
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(person_without_private_data_2, age, name, metadata)
} // namespace persons
TEST_CASE_TEMPLATE("Serialization/deserialization via NLOHMANN_DEFINE_TYPE_INTRUSIVE", T,
persons::person_with_private_data,
persons::person_without_private_data_1,
persons::person_without_private_data_2)
{
SECTION("person")
{
// serialization
T p1("Erik", 1, {{"haircuts", 2}});
CHECK(json(p1).dump() == "{\"age\":1,\"metadata\":{\"haircuts\":2},\"name\":\"Erik\"}");
// deserialization
T p2 = json(p1);
CHECK(p2 == p1);
// roundtrip
CHECK(T(json(p1)) == p1);
CHECK(json(T(json(p1))) == json(p1));
// check exception in case of missing field
json j = json(p1);
j.erase("age");
T p3;
CHECK_THROWS_WITH_AS(p3 = json(j), "[json.exception.out_of_range.403] key 'age' not found", json::out_of_range);
}
}
+22 -22
View File
@@ -217,7 +217,7 @@ TEST_CASE("Unicode" * doctest::skip())
for (int byte1 = 0x00; byte1 <= 0x7F; ++byte1) for (int byte1 = 0x00; byte1 <= 0x7F; ++byte1)
{ {
// unescaped control characters are parse errors in JSON // unescaped control characters are parse errors in JSON
if (0x00 <= byte1 and byte1 <= 0x1F) if (0x00 <= byte1 && byte1 <= 0x1F)
{ {
check_utf8string(false, byte1); check_utf8string(false, byte1);
continue; continue;
@@ -274,7 +274,7 @@ TEST_CASE("Unicode" * doctest::skip())
for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2) for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2)
{ {
// skip correct second byte // skip correct second byte
if (0x80 <= byte2 and byte2 <= 0xBF) if (0x80 <= byte2 && byte2 <= 0xBF)
{ {
continue; continue;
} }
@@ -331,7 +331,7 @@ TEST_CASE("Unicode" * doctest::skip())
for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2) for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2)
{ {
// skip correct second byte // skip correct second byte
if (0xA0 <= byte2 and byte2 <= 0xBF) if (0xA0 <= byte2 && byte2 <= 0xBF)
{ {
continue; continue;
} }
@@ -354,7 +354,7 @@ TEST_CASE("Unicode" * doctest::skip())
for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3) for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3)
{ {
// skip correct third byte // skip correct third byte
if (0x80 <= byte3 and byte3 <= 0xBF) if (0x80 <= byte3 && byte3 <= 0xBF)
{ {
continue; continue;
} }
@@ -412,7 +412,7 @@ TEST_CASE("Unicode" * doctest::skip())
for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2) for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2)
{ {
// skip correct second byte // skip correct second byte
if (0x80 <= byte2 and byte2 <= 0xBF) if (0x80 <= byte2 && byte2 <= 0xBF)
{ {
continue; continue;
} }
@@ -435,7 +435,7 @@ TEST_CASE("Unicode" * doctest::skip())
for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3) for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3)
{ {
// skip correct third byte // skip correct third byte
if (0x80 <= byte3 and byte3 <= 0xBF) if (0x80 <= byte3 && byte3 <= 0xBF)
{ {
continue; continue;
} }
@@ -493,7 +493,7 @@ TEST_CASE("Unicode" * doctest::skip())
for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2) for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2)
{ {
// skip correct second byte // skip correct second byte
if (0x80 <= byte2 and byte2 <= 0x9F) if (0x80 <= byte2 && byte2 <= 0x9F)
{ {
continue; continue;
} }
@@ -516,7 +516,7 @@ TEST_CASE("Unicode" * doctest::skip())
for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3) for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3)
{ {
// skip correct third byte // skip correct third byte
if (0x80 <= byte3 and byte3 <= 0xBF) if (0x80 <= byte3 && byte3 <= 0xBF)
{ {
continue; continue;
} }
@@ -574,7 +574,7 @@ TEST_CASE("Unicode" * doctest::skip())
for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2) for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2)
{ {
// skip correct second byte // skip correct second byte
if (0x80 <= byte2 and byte2 <= 0xBF) if (0x80 <= byte2 && byte2 <= 0xBF)
{ {
continue; continue;
} }
@@ -597,7 +597,7 @@ TEST_CASE("Unicode" * doctest::skip())
for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3) for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3)
{ {
// skip correct third byte // skip correct third byte
if (0x80 <= byte3 and byte3 <= 0xBF) if (0x80 <= byte3 && byte3 <= 0xBF)
{ {
continue; continue;
} }
@@ -673,7 +673,7 @@ TEST_CASE("Unicode" * doctest::skip())
for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2) for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2)
{ {
// skip correct second byte // skip correct second byte
if (0x90 <= byte2 and byte2 <= 0xBF) if (0x90 <= byte2 && byte2 <= 0xBF)
{ {
continue; continue;
} }
@@ -699,7 +699,7 @@ TEST_CASE("Unicode" * doctest::skip())
for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3) for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3)
{ {
// skip correct third byte // skip correct third byte
if (0x80 <= byte3 and byte3 <= 0xBF) if (0x80 <= byte3 && byte3 <= 0xBF)
{ {
continue; continue;
} }
@@ -725,7 +725,7 @@ TEST_CASE("Unicode" * doctest::skip())
for (int byte4 = 0x00; byte4 <= 0xFF; ++byte4) for (int byte4 = 0x00; byte4 <= 0xFF; ++byte4)
{ {
// skip fourth second byte // skip fourth second byte
if (0x80 <= byte3 and byte3 <= 0xBF) if (0x80 <= byte3 && byte3 <= 0xBF)
{ {
continue; continue;
} }
@@ -802,7 +802,7 @@ TEST_CASE("Unicode" * doctest::skip())
for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2) for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2)
{ {
// skip correct second byte // skip correct second byte
if (0x80 <= byte2 and byte2 <= 0xBF) if (0x80 <= byte2 && byte2 <= 0xBF)
{ {
continue; continue;
} }
@@ -828,7 +828,7 @@ TEST_CASE("Unicode" * doctest::skip())
for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3) for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3)
{ {
// skip correct third byte // skip correct third byte
if (0x80 <= byte3 and byte3 <= 0xBF) if (0x80 <= byte3 && byte3 <= 0xBF)
{ {
continue; continue;
} }
@@ -854,7 +854,7 @@ TEST_CASE("Unicode" * doctest::skip())
for (int byte4 = 0x00; byte4 <= 0xFF; ++byte4) for (int byte4 = 0x00; byte4 <= 0xFF; ++byte4)
{ {
// skip correct fourth byte // skip correct fourth byte
if (0x80 <= byte3 and byte3 <= 0xBF) if (0x80 <= byte3 && byte3 <= 0xBF)
{ {
continue; continue;
} }
@@ -931,7 +931,7 @@ TEST_CASE("Unicode" * doctest::skip())
for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2) for (int byte2 = 0x00; byte2 <= 0xFF; ++byte2)
{ {
// skip correct second byte // skip correct second byte
if (0x80 <= byte2 and byte2 <= 0x8F) if (0x80 <= byte2 && byte2 <= 0x8F)
{ {
continue; continue;
} }
@@ -957,7 +957,7 @@ TEST_CASE("Unicode" * doctest::skip())
for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3) for (int byte3 = 0x00; byte3 <= 0xFF; ++byte3)
{ {
// skip correct third byte // skip correct third byte
if (0x80 <= byte3 and byte3 <= 0xBF) if (0x80 <= byte3 && byte3 <= 0xBF)
{ {
continue; continue;
} }
@@ -983,7 +983,7 @@ TEST_CASE("Unicode" * doctest::skip())
for (int byte4 = 0x00; byte4 <= 0xFF; ++byte4) for (int byte4 = 0x00; byte4 <= 0xFF; ++byte4)
{ {
// skip correct fourth byte // skip correct fourth byte
if (0x80 <= byte3 and byte3 <= 0xBF) if (0x80 <= byte3 && byte3 <= 0xBF)
{ {
continue; continue;
} }
@@ -1030,7 +1030,7 @@ TEST_CASE("Unicode" * doctest::skip())
// they will never be assigned a character, so there should be no // they will never be assigned a character, so there should be no
// reason to encode them. The official Unicode standard says that // reason to encode them. The official Unicode standard says that
// no UTF forms, including UTF-16, can encode these code points. // no UTF forms, including UTF-16, can encode these code points.
if (cp >= 0xD800u and cp <= 0xDFFFu) if (cp >= 0xD800u && cp <= 0xDFFFu)
{ {
// if we would not skip these code points, we would get a // if we would not skip these code points, we would get a
// "missing low surrogate" exception // "missing low surrogate" exception
@@ -1117,7 +1117,7 @@ TEST_CASE("Unicode" * doctest::skip())
{ {
for (std::size_t cp2 = 0x0000u; cp2 <= 0xFFFFu; ++cp2) for (std::size_t cp2 = 0x0000u; cp2 <= 0xFFFFu; ++cp2)
{ {
if (0xDC00u <= cp2 and cp2 <= 0xDFFFu) if (0xDC00u <= cp2 && cp2 <= 0xDFFFu)
{ {
continue; continue;
} }
@@ -1163,7 +1163,7 @@ TEST_CASE("Unicode" * doctest::skip())
for (auto s : j) for (auto s : j)
{ {
// skip non-string JSON values // skip non-string JSON values
if (not s.is_string()) if (!s.is_string())
{ {
continue; continue;
} }