diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 8dbacb78..4ae0cb2d 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -54,7 +54,7 @@ To make changes, you need to edit the following files: ## Please don't -- The C++11 support varies between different **compilers** and versions. Please note the [list of supported compilers](https://github.com/nlohmann/json/blob/master/README.md#supported-compilers). Some compilers like GCC 4.8 (and earlier), Clang 3.3 (and earlier), or Microsoft Visual Studio 13.0 and earlier are known not to work due to missing or incomplete C++11 support. Please refrain from proposing changes that work around these compiler's limitations with `#ifdef`s or other means. +- The C++11 support varies between different **compilers** and versions. Please note the [list of supported compilers](https://github.com/nlohmann/json/blob/master/README.md#supported-compilers). Some compilers like GCC 4.7 (and earlier), Clang 3.3 (and earlier), or Microsoft Visual Studio 13.0 and earlier are known not to work due to missing or incomplete C++11 support. Please refrain from proposing changes that work around these compiler's limitations with `#ifdef`s or other means. - Specifically, I am aware of compilation problems with **Microsoft Visual Studio** (there even is an [issue label](https://github.com/nlohmann/json/issues?utf8=✓&q=label%3A%22visual+studio%22+) for these kind of bugs). I understand that even in 2016, complete C++11 support isn't there yet. But please also understand that I do not want to drop features or uglify the code just to make Microsoft's sub-standard compiler happy. The past has shown that there are ways to express the functionality such that the code compiles with the most recent MSVC - unfortunately, this is not the main objective of the project. - Please refrain from proposing changes that would **break [JSON](http://json.org) conformance**. If you propose a conformant extension of JSON to be supported by the library, please motivate this extension. - We shall not extend the library to **support comments**. There is quite some [controversy](https://www.reddit.com/r/programming/comments/4v6chu/why_json_doesnt_support_comments_douglas_crockford/) around this topic, and there were quite some [issues](https://github.com/nlohmann/json/issues/376) on this. We believe that JSON is fine without comments. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index d75a67b4..f2c3af6a 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -13,7 +13,7 @@ Read the [Contribution Guidelines](https://github.com/nlohmann/json/blob/develop ## Please don't -- The C++11 support varies between different **compilers** and versions. Please note the [list of supported compilers](https://github.com/nlohmann/json/blob/master/README.md#supported-compilers). Some compilers like GCC 4.8 (and earlier), Clang 3.3 (and earlier), or Microsoft Visual Studio 13.0 and earlier are known not to work due to missing or incomplete C++11 support. Please refrain from proposing changes that work around these compiler's limitations with `#ifdef`s or other means. +- The C++11 support varies between different **compilers** and versions. Please note the [list of supported compilers](https://github.com/nlohmann/json/blob/master/README.md#supported-compilers). Some compilers like GCC 4.7 (and earlier), Clang 3.3 (and earlier), or Microsoft Visual Studio 13.0 and earlier are known not to work due to missing or incomplete C++11 support. Please refrain from proposing changes that work around these compiler's limitations with `#ifdef`s or other means. - Specifically, I am aware of compilation problems with **Microsoft Visual Studio** (there even is an [issue label](https://github.com/nlohmann/json/issues?utf8=✓&q=label%3A%22visual+studio%22+) for these kind of bugs). I understand that even in 2016, complete C++11 support isn't there yet. But please also understand that I do not want to drop features or uglify the code just to make Microsoft's sub-standard compiler happy. The past has shown that there are ways to express the functionality such that the code compiles with the most recent MSVC - unfortunately, this is not the main objective of the project. - Please refrain from proposing changes that would **break [JSON](http://json.org) conformance**. If you propose a conformant extension of JSON to be supported by the library, please motivate this extension. - Please do not open pull requests that address **multiple issues**. diff --git a/.travis.yml b/.travis.yml index e5f08353..4c539510 100644 --- a/.travis.yml +++ b/.travis.yml @@ -161,11 +161,22 @@ matrix: - os: osx osx_image: xcode9.4 + - os: osx + osx_image: xcode10 + # Linux / GCC - os: linux compiler: gcc - env: COMPILER=g++-4.9 + env: compiler=g++-4.8 + addons: + apt: + sources: ['ubuntu-toolchain-r-test'] + packages: ['g++-4.8', 'ninja-build'] + + - os: linux + compiler: gcc + env: compiler=g++-4.9 addons: apt: sources: ['ubuntu-toolchain-r-test'] diff --git a/CMakeLists.txt b/CMakeLists.txt index b345c77a..e80d7a98 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.8) ## PROJECT ## name and version ## -project(nlohmann_json VERSION 3.2.0 LANGUAGES CXX) +project(nlohmann_json VERSION 3.3.0 LANGUAGES CXX) ## ## INCLUDE @@ -86,10 +86,10 @@ include(CMakePackageConfigHelpers) write_basic_package_version_file( ${NLOHMANN_JSON_CMAKE_VERSION_CONFIG_FILE} COMPATIBILITY SameMajorVersion ) -configure_package_config_file( +configure_file( ${NLOHMANN_JSON_CMAKE_CONFIG_TEMPLATE} ${NLOHMANN_JSON_CMAKE_PROJECT_CONFIG_FILE} - INSTALL_DESTINATION ${NLOHMANN_JSON_CONFIG_INSTALL_DIR} + @ONLY ) install( diff --git a/ChangeLog.md b/ChangeLog.md index 0c6cc009..19b69d2a 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,7 +1,75 @@ # Change Log All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). -## [v3.2.0](https://github.com/nlohmann/json/releases/tag/v3.2.0) (2018-08-18) +## [v3.3.0](https://github.com/nlohmann/json/releases/tag/v3.3.0) (2018-10-05) +[Full Changelog](https://github.com/nlohmann/json/compare/v3.2.0...v3.3.0) + +- When key is not found print the key name into error too [\#1273](https://github.com/nlohmann/json/issues/1273) +- Visual Studio 2017 15.8.5 "conditional expression is constant" warning on Line 1851 in json.hpp [\#1268](https://github.com/nlohmann/json/issues/1268) +- how can we get this working on WSL? [\#1264](https://github.com/nlohmann/json/issues/1264) +- Help needed [\#1259](https://github.com/nlohmann/json/issues/1259) +- A way to get to a JSON values "key" [\#1258](https://github.com/nlohmann/json/issues/1258) +- Two blackslashes on json output file [\#1253](https://github.com/nlohmann/json/issues/1253) +- Including nlohmann the badwrong way. [\#1250](https://github.com/nlohmann/json/issues/1250) +- how to build with clang? [\#1247](https://github.com/nlohmann/json/issues/1247) +- Cmake target\_link\_libraries unable to find nlohmann\_json since version 3.2.0 [\#1243](https://github.com/nlohmann/json/issues/1243) +- \[Question\] Access to end\(\) iterator reference [\#1242](https://github.com/nlohmann/json/issues/1242) +- Parsing different json format [\#1241](https://github.com/nlohmann/json/issues/1241) +- Parsing Multiple JSON Files [\#1240](https://github.com/nlohmann/json/issues/1240) +- Doesn't compile under C++17 [\#1239](https://github.com/nlohmann/json/issues/1239) +- Conversion operator for nlohmann::json is not SFINAE friendly [\#1237](https://github.com/nlohmann/json/issues/1237) +- Custom deserialization of number\_float\_t [\#1236](https://github.com/nlohmann/json/issues/1236) +- Move tests to a separate repo [\#1235](https://github.com/nlohmann/json/issues/1235) +- deprecated-declarations warnings when compiling tests with GCC 8.2.1. [\#1233](https://github.com/nlohmann/json/issues/1233) +- Incomplete type with json\_fwd.hpp [\#1232](https://github.com/nlohmann/json/issues/1232) +- Parse Error [\#1229](https://github.com/nlohmann/json/issues/1229) +- json::get function with argument [\#1227](https://github.com/nlohmann/json/issues/1227) +- questions regarding from\_json [\#1226](https://github.com/nlohmann/json/issues/1226) +- Lambda in unevaluated context [\#1225](https://github.com/nlohmann/json/issues/1225) +- NLohmann doesn't compile when enabling strict warning policies [\#1224](https://github.com/nlohmann/json/issues/1224) +- Creating array of objects [\#1223](https://github.com/nlohmann/json/issues/1223) +- Somewhat unhelpful error message "cannot use operator\[\] with object" [\#1220](https://github.com/nlohmann/json/issues/1220) +- single\_include json.hpp [\#1218](https://github.com/nlohmann/json/issues/1218) +- Maps with enum class keys which are convertible to JSON strings should be converted to JSON dictionaries [\#1217](https://github.com/nlohmann/json/issues/1217) +- Adding JSON Array to the Array [\#1216](https://github.com/nlohmann/json/issues/1216) +- Best way to output a vector of a given type to json [\#1215](https://github.com/nlohmann/json/issues/1215) +- compiler warning: double definition of macro JSON\_INTERNAL\_CATCH [\#1213](https://github.com/nlohmann/json/issues/1213) +- Compilation error when using MOCK\_METHOD1 from GMock and nlohmann::json [\#1212](https://github.com/nlohmann/json/issues/1212) +- Issues parsing a previously encoded binary \(non-UTF8\) string. [\#1211](https://github.com/nlohmann/json/issues/1211) +- Yet another ordering question: char \* and parse\(\) [\#1209](https://github.com/nlohmann/json/issues/1209) +- Error using gcc 8.1.0 on Ubuntu 14.04 [\#1207](https://github.com/nlohmann/json/issues/1207) +- "type must be string, but is " std::string\(j.type\_name\(\) [\#1206](https://github.com/nlohmann/json/issues/1206) +- Returning empty json object from a function of type const json& ? [\#1205](https://github.com/nlohmann/json/issues/1205) +- VS2017 compiler suggests using constexpr if [\#1204](https://github.com/nlohmann/json/issues/1204) +- Template instatiation error on compiling [\#1203](https://github.com/nlohmann/json/issues/1203) +- Soften the landing when dumping non-UTF8 strings \(type\_error.316 exception\) [\#1198](https://github.com/nlohmann/json/issues/1198) +- BUG - json dump field with unicode -\> array of ints \(instead of string\) [\#1197](https://github.com/nlohmann/json/issues/1197) +- Compile error using Code::Blocks // mingw-w64 GCC 8.1.0 - "Incomplete Type" [\#1193](https://github.com/nlohmann/json/issues/1193) +- SEGFAULT on arm target [\#1190](https://github.com/nlohmann/json/issues/1190) +- Compiler crash with old Clang [\#1179](https://github.com/nlohmann/json/issues/1179) +- Custom Precision on floating point numbers [\#1170](https://github.com/nlohmann/json/issues/1170) +- Can we have a json\_view class like std::string\_view? [\#1158](https://github.com/nlohmann/json/issues/1158) +- improve error handling [\#1152](https://github.com/nlohmann/json/issues/1152) +- We should remove static\_asserts [\#960](https://github.com/nlohmann/json/issues/960) + +- Fix warning C4127: conditional expression is constant [\#1272](https://github.com/nlohmann/json/pull/1272) ([antonioborondo](https://github.com/antonioborondo)) +- Turn off additional deprecation warnings for GCC. [\#1271](https://github.com/nlohmann/json/pull/1271) ([chuckatkins](https://github.com/chuckatkins)) +- docs: Add additional CMake documentation [\#1270](https://github.com/nlohmann/json/pull/1270) ([chuckatkins](https://github.com/chuckatkins)) +- unit-testsuites.cpp: fix hangup if file not found [\#1262](https://github.com/nlohmann/json/pull/1262) ([knilch0r](https://github.com/knilch0r)) +- Fix broken cmake imported target alias [\#1260](https://github.com/nlohmann/json/pull/1260) ([chuckatkins](https://github.com/chuckatkins)) +- GCC 48 [\#1257](https://github.com/nlohmann/json/pull/1257) ([henryiii](https://github.com/henryiii)) +- Add version and license to meson.build [\#1252](https://github.com/nlohmann/json/pull/1252) ([koponomarenko](https://github.com/koponomarenko)) +- \#1179 Reordered the code. It seems to stop clang 3.4.2 in RHEL 7 from crash… [\#1249](https://github.com/nlohmann/json/pull/1249) ([LEgregius](https://github.com/LEgregius)) +- Use a version check to provide backwards comatible CMake imported target names [\#1245](https://github.com/nlohmann/json/pull/1245) ([chuckatkins](https://github.com/chuckatkins)) +- Fix issue \#1237 [\#1238](https://github.com/nlohmann/json/pull/1238) ([theodelrieu](https://github.com/theodelrieu)) +- Add a get overload taking a parameter. [\#1231](https://github.com/nlohmann/json/pull/1231) ([theodelrieu](https://github.com/theodelrieu)) +- Move lambda out of unevaluated context [\#1230](https://github.com/nlohmann/json/pull/1230) ([mandreyel](https://github.com/mandreyel)) +- Remove static asserts [\#1228](https://github.com/nlohmann/json/pull/1228) ([theodelrieu](https://github.com/theodelrieu)) +- Better error 305 [\#1221](https://github.com/nlohmann/json/pull/1221) ([rivertam](https://github.com/rivertam)) +- Fix \#1213 [\#1214](https://github.com/nlohmann/json/pull/1214) ([simnalamburt](https://github.com/simnalamburt)) +- Export package to allow builds without installing [\#1202](https://github.com/nlohmann/json/pull/1202) ([dennisfischer](https://github.com/dennisfischer)) + +## [v3.2.0](https://github.com/nlohmann/json/releases/tag/v3.2.0) (2018-08-20) [Full Changelog](https://github.com/nlohmann/json/compare/v3.1.2...v3.2.0) - Am I doing this wrong? Getting an empty string [\#1199](https://github.com/nlohmann/json/issues/1199) @@ -964,7 +1032,6 @@ All notable changes to this project will be documented in this file. This projec - json::diff generates incorrect patch when removing multiple array elements. [\#269](https://github.com/nlohmann/json/issues/269) - Docs - What does Json\[key\] return? [\#267](https://github.com/nlohmann/json/issues/267) - Compiler Errors With JSON.hpp [\#265](https://github.com/nlohmann/json/issues/265) -- Throw exception instead of crashing my app [\#264](https://github.com/nlohmann/json/issues/264) - Ambiguous push\_back and operator+= overloads [\#263](https://github.com/nlohmann/json/issues/263) - Preseving order of items in json [\#262](https://github.com/nlohmann/json/issues/262) - '\' char problem in strings [\#261](https://github.com/nlohmann/json/issues/261) diff --git a/Makefile b/Makefile index 1deb8da5..bfb62349 100644 --- a/Makefile +++ b/Makefile @@ -191,7 +191,10 @@ pedantic_gcc: -Wunused-macros \ -Wunused-parameter \ -Wuseless-cast \ - -Wvariadic-macros" + -Wvariadic-macros \ + -Wctor-dtor-privacy \ + -Winit-self \ + -Wstrict-null-sentinel" ########################################################################## # benchmarks diff --git a/README.md b/README.md index f3bbf847..926b4d7e 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ [](https://coveralls.io/r/nlohmann/json) [](https://scan.coverity.com/projects/nlohmann-json) [](https://www.codacy.com/app/nlohmann/json?utm_source=github.com&utm_medium=referral&utm_content=nlohmann/json&utm_campaign=Badge_Grade) +[](https://lgtm.com/projects/g/nlohmann/json/context:cpp) [](https://wandbox.org/permlink/TarF5pPn9NtHQjhf) [](http://nlohmann.github.io/json) [](https://raw.githubusercontent.com/nlohmann/json/master/LICENSE.MIT) @@ -15,6 +16,8 @@ - [Design goals](#design-goals) - [Integration](#integration) + - [CMake](#cmake) + - [Package Managers](#package-managers) - [Examples](#examples) - [JSON as first-class data type](#json-as-first-class-data-type) - [Serialization / Deserialization](#serialization--deserialization) @@ -68,6 +71,71 @@ to the files you want to process JSON and set the necessary switches to enable C You can further use file [`include/nlohmann/json_fwd.hpp`](https://github.com/nlohmann/json/blob/develop/include/nlohmann/json_fwd.hpp) for forward-declarations. The installation of json_fwd.hpp (as part of cmake's install step), can be achieved by setting `-DJSON_MultipleHeaders=ON`. +### CMake + +You can also use the `nlohmann_json::nlohmann_json` interface target in CMake. This target populates the appropriate usage requirements for `INTERFACE_INCLUDE_DIRECTORIES` to point to the appropriate include directories and `INTERFACE_COMPILE_FEATURES` for the necessary C++11 flags. + +#### External + +To use this library from a CMake project, you can locate it directly with `find_package()` and use the namespaced imported target from the generated package configuration: +```cmake +# CMakeLists.txt +find_package(nlohmann_json 3.2.0 REQUIRED) +... +add_library(foo ...) +... +target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json) +``` +The package configuration file, `nlohmann_jsonConfig.cmake`, can be used either from an install tree or directly out of the build tree. + +#### Embedded + +To embed the library directly into an existing CMake project, place the entire source tree in a subdirectory and call `add_subdirectory()` in your `CMakeLists.txt` file: +```cmake +# Typically you don't care so much for a third party library's tests to be +# run from your own project's code. +set(JSON_BuildTests OFF CACHE INTERNAL "") + +# Don't use include(nlohmann_json/CMakeLists.txt) since that carries with it +# inintended consequences that will break the build. It's generally +# discouraged (although not necessarily well documented as such) to use +# include(...) for pulling in other CMake projects anyways. +add_subdirectory(nlohmann_json) +... +add_library(foo ...) +... +target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json) +``` + +#### Supporting Both +To allow your project to support either an externally supplied or an embedded JSON library, you can use a pattern akin to the following: +``` cmake +# Top level CMakeLists.txt +project(FOO) +... +option(FOO_USE_EXTERNAL_JSON "Use an external JSON library" OFF) +... +add_subdirectory(thirdparty) +... +add_library(foo ...) +... +# Note that the namespaced target will always be available regardless of the +# import method +target_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json) +``` +```cmake +# thirdparty/CMakeLists.txt +... +if(FOO_USE_EXTERNAL_JSON) + find_package(nlohmann_json 3.2.0 REQUIRED) +else() + set(JSON_BuildTests OFF CACHE INTERNAL "") + add_subdirectory(nlohmann_json) +endif() +... +``` +`thirdparty/nlohmann_json` is then a complete copy of this source tree. + ### Package Managers :beer: If you are using OS X and [Homebrew](http://brew.sh), just type `brew tap nlohmann/json` and `brew install nlohmann_json` and you're set. If you want the bleeding edge rather than the latest release, use `brew install nlohmann_json --HEAD`. @@ -226,12 +294,15 @@ json j_string = "this is a string"; std::string cpp_string = j_string; // retrieve the string value (explicit JSON to std::string conversion) auto cpp_string2 = j_string.get<std::string>(); +// retrieve the string value (alternative explicit JSON to std::string conversion) +std::string cpp_string3; +j_string.get_to(cpp_string3); // retrieve the serialized value (explicit JSON serialization) std::string serialized_string = j_string.dump(); // output of original string -std::cout << cpp_string << " == " << cpp_string2 << " == " << j_string.get<std::string>() << '\n'; +std::cout << cpp_string << " == " << cpp_string2 << " == " << cpp_string3 << " == " << j_string.get<std::string>() << '\n'; // output of serialized value std::cout << j_string << " == " << serialized_string << std::endl; ``` @@ -642,15 +713,15 @@ namespace ns { } void from_json(const json& j, person& p) { - p.name = j.at("name").get<std::string>(); - p.address = j.at("address").get<std::string>(); - p.age = j.at("age").get<int>(); + j.at("name").get_to(p.name); + j.at("address").get_to(p.address); + j.at("age").get_to(p.age); } } // namespace ns ``` That's all! When calling the `json` constructor with your type, your custom `to_json` method will be automatically called. -Likewise, when calling `get<your_type>()`, the `from_json` method will be called. +Likewise, when calling `get<your_type>()` or `get_to(your_type&)`, the `from_json` method will be called. Some important things: @@ -658,9 +729,8 @@ Some important things: * Those methods **MUST** be available (e.g., properly headers must be included) everywhere you use the implicit conversions. Look at [issue 1108](https://github.com/nlohmann/json/issues/1108) for errors that may occur otherwise. * When using `get<your_type>()`, `your_type` **MUST** be [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible). (There is a way to bypass this requirement described later.) * In function `from_json`, use function [`at()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a93403e803947b86f4da2d1fb3345cf2c.html#a93403e803947b86f4da2d1fb3345cf2c) to access the object values rather than `operator[]`. In case a key does not exist, `at` throws an exception that you can handle, whereas `operator[]` exhibits undefined behavior. -* In case your type contains several `operator=` definitions, code like `your_variable = your_json;` [may not compile](https://github.com/nlohmann/json/issues/667). You need to write `your_variable = your_json.get<decltype your_variable>();` instead. +* In case your type contains several `operator=` definitions, code like `your_variable = your_json;` [may not compile](https://github.com/nlohmann/json/issues/667). You need to write `your_variable = your_json.get<decltype(your_variable)>();` or `your_json.get_to(your_variable);` instead. * You do not need to add serializers or deserializers for STL types like `std::vector`: the library already implements these. -* Be careful with the definition order of the `from_json`/`to_json` functions: If a type `B` has a member of type `A`, you **MUST** define `to_json(A)` before `to_json(B)`. Look at [issue 561](https://github.com/nlohmann/json/issues/561) for more details. #### How do I convert third-party types? @@ -842,7 +912,7 @@ json j_from_ubjson = json::from_ubjson(v_ubjson); Though it's 2018 already, the support for C++11 is still a bit sparse. Currently, the following compilers are known to work: -- GCC 4.9 - 8.2 (and possibly later) +- GCC 4.8 - 8.2 (and possibly later) - Clang 3.4 - 6.1 (and possibly later) - Intel C++ Compiler 17.0.2 (and possibly later) - Microsoft Visual C++ 2015 / Build Tools 14.0.25123.0 (and possibly later) @@ -852,7 +922,7 @@ I would be happy to learn about other compilers/versions. Please note: -- GCC 4.8 does not work because of two bugs ([55817](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55817) and [57824](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57824)) in the C++11 support. Note there is a [pull request](https://github.com/nlohmann/json/pull/212) to fix some of the issues. +- GCC 4.8 has a bug [57824](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57824)): multiline raw strings cannot be the arguments to macros. Don't use multiline raw strings directly in macros with this compiler. - Android defaults to using very old compilers and C++ libraries. To fix this, add the following to your `Application.mk`. This will switch to the LLVM C++ library, the Clang compiler, and enable C++11 and other features disabled by default. ``` @@ -871,6 +941,7 @@ The following compilers are currently used in continuous integration at [Travis] | Compiler | Operating System | Version String | |-----------------|------------------------------|----------------| +| GCC 4.8.5 | Ubuntu 14.04.5 LTS | g++-4.8 (Ubuntu 4.8.5-2ubuntu1~14.04.2) 4.8.5 | | GCC 4.9.4 | Ubuntu 14.04.1 LTS | g++-4.9 (Ubuntu 4.9.4-2ubuntu1~14.04.1) 4.9.4 | | GCC 5.5.0 | Ubuntu 14.04.1 LTS | g++-5 (Ubuntu 5.5.0-12ubuntu1~14.04) 5.5.0 20171010 | | GCC 6.4.0 | Ubuntu 14.04.1 LTS | g++-6 (Ubuntu 6.4.0-17ubuntu1~14.04) 6.4.0 20180424 | @@ -895,6 +966,7 @@ The following compilers are currently used in continuous integration at [Travis] | Clang Xcode 9.1 | OSX 10.12.6 | Apple LLVM version 9.0.0 (clang-900.0.38) | | Clang Xcode 9.2 | OSX 10.13.3 | Apple LLVM version 9.1.0 (clang-902.0.39.1) | | Clang Xcode 9.3 | OSX 10.13.3 | Apple LLVM version 9.1.0 (clang-902.0.39.2) | +| Clang Xcode 10.0 | OSX 10.13.3 | Apple LLVM version 10.0.0 (clang-1000.11.45.2) | | Visual Studio 14 2015 | Windows Server 2012 R2 (x64) | Microsoft (R) Build Engine version 14.0.25420.1, MSVC 19.0.24215.1 | | Visual Studio 2017 | Windows Server 2016 | Microsoft (R) Build Engine version 15.7.180.61344, MSVC 19.14.26433.0 | @@ -1045,7 +1117,7 @@ I deeply appreciate the help of the following people. - [Axel Huebl](https://github.com/ax3l) simplified a CMake check and added support for the [Spack package manager](https://spack.io). - [Carlos O'Ryan](https://github.com/coryan) fixed a typo. - [James Upjohn](https://github.com/jammehcow) fixed a version number in the compilers section. -- [Chuck Atkins](https://github.com/chuckatkins) adjusted the CMake files to the CMake packaging guidelines +- [Chuck Atkins](https://github.com/chuckatkins) adjusted the CMake files to the CMake packaging guidelines and provided documentation for the CMake integration. - [Jan Schöppach](https://github.com/dns13) fixed a typo. - [martin-mfg](https://github.com/martin-mfg) fixed a typo. - [Matthias Möller](https://github.com/TinyTinni) removed the dependency from `std::stringstream`. @@ -1056,6 +1128,16 @@ I deeply appreciate the help of the following people. - [grembo](https://github.com/grembo) fixed the test suite and re-enabled several test cases. - [Hyeon Kim](https://github.com/simnalamburt) introduced the macro `JSON_INTERNAL_CATCH` to control the exception handling inside the library. - [thyu](https://github.com/thyu) fixed a compiler warning. +- [David Guthrie](https://github.com/LEgregius) fixed a subtle compilation error with Clang 3.4.2. +- [Dennis Fischer](https://github.com/dennisfischer) allowed to call `find_package` without installing the library. +- [Hyeon Kim](https://github.com/simnalamburt) fixed an issue with a double macro definition. +- [Ben Berman](https://github.com/rivertam) made some error messages more understandable. +- [zakalibit](https://github.com/zakalibit) fixed a compilation problem with the Intel C++ compiler. +- [mandreyel](https://github.com/mandreyel) fixed a compilation problem. +- [Kostiantyn Ponomarenko](https://github.com/koponomarenko) added version and license information to the Meson build file. +- [Henry Schreiner](https://github.com/henryiii) added support for GCC 4.8. +- [knilch](https://github.com/knilch0r) made sure the test suite does not stall when run in the wrong directory. +- [Antonio Borondo](https://github.com/antonioborondo) fixed an MSVC 2017 warning. Thanks a lot for helping out! Please [let me know](mailto:mail@nlohmann.me) if I forgot someone. diff --git a/cmake/config.cmake.in b/cmake/config.cmake.in index 8baabf07..9a17a7d7 100644 --- a/cmake/config.cmake.in +++ b/cmake/config.cmake.in @@ -1,5 +1,15 @@ -@PACKAGE_INIT@ +include(FindPackageHandleStandardArgs) +set(${CMAKE_FIND_PACKAGE_NAME}_CONFIG ${CMAKE_CURRENT_LIST_FILE}) +find_package_handle_standard_args(@PROJECT_NAME@ CONFIG_MODE) + if(NOT TARGET @PROJECT_NAME@::@NLOHMANN_JSON_TARGET_NAME@) include("${CMAKE_CURRENT_LIST_DIR}/@NLOHMANN_JSON_TARGETS_EXPORT_NAME@.cmake") + if((NOT TARGET @NLOHMANN_JSON_TARGET_NAME@) AND + (NOT @PROJECT_NAME@_FIND_VERSION OR + @PROJECT_NAME@_FIND_VERSION VERSION_LESS 3.2.0)) + add_library(@NLOHMANN_JSON_TARGET_NAME@ INTERFACE IMPORTED) + set_target_properties(@NLOHMANN_JSON_TARGET_NAME@ PROPERTIES + INTERFACE_LINK_LIBRARIES @PROJECT_NAME@::@NLOHMANN_JSON_TARGET_NAME@ + ) + endif() endif() -check_required_components("@PROJECT_NAME@") diff --git a/doc/Doxyfile b/doc/Doxyfile index f9512640..87d234ff 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -5,7 +5,7 @@ #--------------------------------------------------------------------------- DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = "JSON for Modern C++" -PROJECT_NUMBER = 3.2.0 +PROJECT_NUMBER = 3.3.0 PROJECT_BRIEF = PROJECT_LOGO = OUTPUT_DIRECTORY = . diff --git a/doc/avatars.png b/doc/avatars.png index 4798d3ba..876802da 100644 Binary files a/doc/avatars.png and b/doc/avatars.png differ diff --git a/doc/examples/README.link b/doc/examples/README.link index a9d70c40..5b620f23 100644 --- a/doc/examples/README.link +++ b/doc/examples/README.link @@ -1 +1 @@ -<a target="_blank" href="https://wandbox.org/permlink/VexEaSCbbvOOXsPt"><b>online</b></a> \ No newline at end of file +<a target="_blank" href="https://wandbox.org/permlink/RWX63GizBsDZ5EnQ"><b>online</b></a> \ No newline at end of file diff --git a/doc/examples/get_to.cpp b/doc/examples/get_to.cpp new file mode 100644 index 00000000..4705b172 --- /dev/null +++ b/doc/examples/get_to.cpp @@ -0,0 +1,60 @@ +#include <iostream> +#include <unordered_map> +#include <nlohmann/json.hpp> + +using json = nlohmann::json; + +int main() +{ + // create a JSON value with different types + json json_types = + { + {"boolean", true}, + { + "number", { + {"integer", 42}, + {"floating-point", 17.23} + } + }, + {"string", "Hello, world!"}, + {"array", {1, 2, 3, 4, 5}}, + {"null", nullptr} + }; + + bool v1; + int v2; + short v3; + float v4; + int v5; + std::string v6; + std::vector<short> v7; + std::unordered_map<std::string, json> v8; + + + // use explicit conversions + json_types["boolean"].get_to(v1); + json_types["number"]["integer"].get_to(v2); + json_types["number"]["integer"].get_to(v3); + json_types["number"]["floating-point"].get_to(v4); + json_types["number"]["floating-point"].get_to(v5); + json_types["string"].get_to(v6); + json_types["array"].get_to(v7); + json_types.get_to(v8); + + // print the conversion results + std::cout << v1 << '\n'; + std::cout << v2 << ' ' << v3 << '\n'; + std::cout << v4 << ' ' << v5 << '\n'; + std::cout << v6 << '\n'; + + for (auto i : v7) + { + std::cout << i << ' '; + } + std::cout << "\n\n"; + + for (auto i : v8) + { + std::cout << i.first << ": " << i.second << '\n'; + } +} diff --git a/doc/examples/get_to.link b/doc/examples/get_to.link new file mode 100644 index 00000000..02a167b0 --- /dev/null +++ b/doc/examples/get_to.link @@ -0,0 +1 @@ +<a target="_blank" href="https://wandbox.org/permlink/QxtxaO6JZAMJPutC"><b>online</b></a> \ No newline at end of file diff --git a/doc/examples/get_to.output b/doc/examples/get_to.output new file mode 100644 index 00000000..5cd9cd3a --- /dev/null +++ b/doc/examples/get_to.output @@ -0,0 +1,11 @@ +1 +42 42 +17.23 17 +Hello, world! +1 2 3 4 5 + +string: "Hello, world!" +number: {"floating-point":17.23,"integer":42} +null: null +boolean: true +array: [1,2,3,4,5] diff --git a/doc/examples/meta.output b/doc/examples/meta.output index 3683a17c..a21937f2 100644 --- a/doc/examples/meta.output +++ b/doc/examples/meta.output @@ -2,7 +2,7 @@ "compiler": { "c++": "201103", "family": "clang", - "version": "9.1.0 (clang-902.0.39.2)" + "version": "10.0.0 (clang-1000.10.43.1)" }, "copyright": "(C) 2013-2017 Niels Lohmann", "name": "JSON for Modern C++", @@ -10,8 +10,8 @@ "url": "https://github.com/nlohmann/json", "version": { "major": 3, - "minor": 2, + "minor": 3, "patch": 0, - "string": "3.2.0" + "string": "3.3.0" } } diff --git a/doc/index.md b/doc/index.md index a2ad364b..53faa347 100644 --- a/doc/index.md +++ b/doc/index.md @@ -306,4 +306,4 @@ Note that this table only lists those exceptions thrown due to the type. For ins @author [Niels Lohmann](http://nlohmann.me) @see https://github.com/nlohmann/json to download the source code -@version 3.2.0 +@version 3.3.0 diff --git a/doc/json.gif b/doc/json.gif index 0c00d9fc..03cb06eb 100644 Binary files a/doc/json.gif and b/doc/json.gif differ diff --git a/include/nlohmann/adl_serializer.hpp b/include/nlohmann/adl_serializer.hpp index 53c9009f..0c28d1c7 100644 --- a/include/nlohmann/adl_serializer.hpp +++ b/include/nlohmann/adl_serializer.hpp @@ -20,8 +20,10 @@ struct adl_serializer @param[in,out] val value to write to */ template<typename BasicJsonType, typename ValueType> - static void from_json(BasicJsonType&& j, ValueType& val) noexcept( - noexcept(::nlohmann::from_json(std::forward<BasicJsonType>(j), val))) + static auto from_json(BasicJsonType&& j, ValueType& val) noexcept( + noexcept(::nlohmann::from_json(std::forward<BasicJsonType>(j), val))) -> decltype( + ::nlohmann::from_json(std::forward<BasicJsonType>(j), val), void() + ) { ::nlohmann::from_json(std::forward<BasicJsonType>(j), val); } @@ -35,9 +37,11 @@ struct adl_serializer @param[in,out] j JSON value to write to @param[in] val value to read from */ - template<typename BasicJsonType, typename ValueType> - static void to_json(BasicJsonType& j, ValueType&& val) noexcept( + template <typename BasicJsonType, typename ValueType> + static auto to_json(BasicJsonType& j, ValueType&& val) noexcept( noexcept(::nlohmann::to_json(j, std::forward<ValueType>(val)))) + -> decltype(::nlohmann::to_json(j, std::forward<ValueType>(val)), + void()) { ::nlohmann::to_json(j, std::forward<ValueType>(val)); } diff --git a/include/nlohmann/detail/conversions/from_json.hpp b/include/nlohmann/detail/conversions/from_json.hpp index 5956352f..2375d066 100644 --- a/include/nlohmann/detail/conversions/from_json.hpp +++ b/include/nlohmann/detail/conversions/from_json.hpp @@ -127,16 +127,6 @@ void from_json(const BasicJsonType& j, EnumType& e) e = static_cast<EnumType>(val); } -template<typename BasicJsonType> -void from_json(const BasicJsonType& j, typename BasicJsonType::array_t& arr) -{ - if (JSON_UNLIKELY(not j.is_array())) - { - JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); - } - arr = *j.template get_ptr<const typename BasicJsonType::array_t*>(); -} - // forward_list doesn't have an insert method template<typename BasicJsonType, typename T, typename Allocator, enable_if_t<std::is_convertible<BasicJsonType, T>::value, int> = 0> @@ -166,24 +156,28 @@ void from_json(const BasicJsonType& j, std::valarray<T>& l) std::copy(j.m_value.array->begin(), j.m_value.array->end(), std::begin(l)); } -template<typename BasicJsonType, typename CompatibleArrayType> -void from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<0> /*unused*/) +template<typename BasicJsonType> +void from_json_array_impl(const BasicJsonType& j, typename BasicJsonType::array_t& arr, priority_tag<3> /*unused*/) { - using std::end; + arr = *j.template get_ptr<const typename BasicJsonType::array_t*>(); +} - std::transform(j.begin(), j.end(), - std::inserter(arr, end(arr)), [](const BasicJsonType & i) +template <typename BasicJsonType, typename T, std::size_t N> +auto from_json_array_impl(const BasicJsonType& j, std::array<T, N>& arr, + priority_tag<2> /*unused*/) +-> decltype(j.template get<T>(), void()) +{ + for (std::size_t i = 0; i < N; ++i) { - // get<BasicJsonType>() returns *this, this won't call a from_json - // method when value_type is BasicJsonType - return i.template get<typename CompatibleArrayType::value_type>(); - }); + arr[i] = j.at(i).template get<T>(); + } } template<typename BasicJsonType, typename CompatibleArrayType> auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<1> /*unused*/) -> decltype( arr.reserve(std::declval<typename CompatibleArrayType::size_type>()), + j.template get<typename CompatibleArrayType::value_type>(), void()) { using std::end; @@ -198,25 +192,34 @@ auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, prio }); } -template<typename BasicJsonType, typename T, std::size_t N> -void from_json_array_impl(const BasicJsonType& j, std::array<T, N>& arr, priority_tag<2> /*unused*/) +template <typename BasicJsonType, typename CompatibleArrayType> +void from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, + priority_tag<0> /*unused*/) { - for (std::size_t i = 0; i < N; ++i) + using std::end; + + std::transform( + j.begin(), j.end(), std::inserter(arr, end(arr)), + [](const BasicJsonType & i) { - arr[i] = j.at(i).template get<T>(); - } + // get<BasicJsonType>() returns *this, this won't call a from_json + // method when value_type is BasicJsonType + return i.template get<typename CompatibleArrayType::value_type>(); + }); } -template < - typename BasicJsonType, typename CompatibleArrayType, - enable_if_t < - is_compatible_array_type<BasicJsonType, CompatibleArrayType>::value and - not std::is_same<typename BasicJsonType::array_t, - CompatibleArrayType>::value and - std::is_constructible < - BasicJsonType, typename CompatibleArrayType::value_type >::value, - int > = 0 > -void from_json(const BasicJsonType& j, CompatibleArrayType& arr) +template <typename BasicJsonType, typename CompatibleArrayType, + enable_if_t < + is_compatible_array_type<BasicJsonType, CompatibleArrayType>::value and + not is_compatible_object_type<BasicJsonType, CompatibleArrayType>::value and + not is_compatible_string_type<BasicJsonType, CompatibleArrayType>::value and + not is_basic_json<CompatibleArrayType>::value, + int > = 0 > + +auto from_json(const BasicJsonType& j, CompatibleArrayType& arr) +-> decltype(from_json_array_impl(j, arr, priority_tag<3> {}), +j.template get<typename CompatibleArrayType::value_type>(), +void()) { if (JSON_UNLIKELY(not j.is_array())) { @@ -224,7 +227,7 @@ void from_json(const BasicJsonType& j, CompatibleArrayType& arr) std::string(j.type_name()))); } - from_json_array_impl(j, arr, priority_tag<2> {}); + from_json_array_impl(j, arr, priority_tag<3> {}); } template<typename BasicJsonType, typename CompatibleObjectType, @@ -347,35 +350,13 @@ void from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyE struct from_json_fn { - private: template<typename BasicJsonType, typename T> - auto call(const BasicJsonType& j, T& val, priority_tag<1> /*unused*/) const + auto operator()(const BasicJsonType& j, T& val) const noexcept(noexcept(from_json(j, val))) -> decltype(from_json(j, val), void()) { return from_json(j, val); } - - template<typename BasicJsonType, typename T> - void call(const BasicJsonType& /*unused*/, T& /*unused*/, priority_tag<0> /*unused*/) const noexcept - { - static_assert(sizeof(BasicJsonType) == 0, - "could not find from_json() method in T's namespace"); -#ifdef _MSC_VER - // MSVC does not show a stacktrace for the above assert - using decayed = uncvref_t<T>; - static_assert(sizeof(typename decayed::force_msvc_stacktrace) == 0, - "forcing MSVC stacktrace to show which T we're talking about."); -#endif - } - - public: - template<typename BasicJsonType, typename T> - void operator()(const BasicJsonType& j, T& val) const - noexcept(noexcept(std::declval<from_json_fn>().call(j, val, priority_tag<1> {}))) - { - return call(j, val, priority_tag<1> {}); - } }; } diff --git a/include/nlohmann/detail/conversions/to_json.hpp b/include/nlohmann/detail/conversions/to_json.hpp index 35be5de4..0a802369 100644 --- a/include/nlohmann/detail/conversions/to_json.hpp +++ b/include/nlohmann/detail/conversions/to_json.hpp @@ -248,10 +248,14 @@ void to_json(BasicJsonType& j, const std::vector<bool>& e) external_constructor<value_t::array>::construct(j, e); } -template<typename BasicJsonType, typename CompatibleArrayType, - enable_if_t<is_compatible_array_type<BasicJsonType, CompatibleArrayType>::value or - std::is_same<typename BasicJsonType::array_t, CompatibleArrayType>::value, - int> = 0> +template <typename BasicJsonType, typename CompatibleArrayType, + enable_if_t<is_compatible_array_type<BasicJsonType, + CompatibleArrayType>::value and + not is_compatible_object_type< + BasicJsonType, CompatibleArrayType>::value and + not is_compatible_string_type<BasicJsonType, CompatibleArrayType>::value and + not is_basic_json<CompatibleArrayType>::value, + int> = 0> void to_json(BasicJsonType& j, const CompatibleArrayType& arr) { external_constructor<value_t::array>::construct(j, arr); @@ -271,7 +275,7 @@ void to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr) } template<typename BasicJsonType, typename CompatibleObjectType, - enable_if_t<is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value, int> = 0> + enable_if_t<is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value and not is_basic_json<CompatibleObjectType>::value, int> = 0> void to_json(BasicJsonType& j, const CompatibleObjectType& obj) { external_constructor<value_t::object>::construct(j, obj); @@ -283,9 +287,12 @@ void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj) external_constructor<value_t::object>::construct(j, std::move(obj)); } -template<typename BasicJsonType, typename T, std::size_t N, - enable_if_t<not std::is_constructible<typename BasicJsonType::string_t, T (&)[N]>::value, int> = 0> -void to_json(BasicJsonType& j, T (&arr)[N]) +template < + typename BasicJsonType, typename T, std::size_t N, + enable_if_t<not std::is_constructible<typename BasicJsonType::string_t, + const T (&)[N]>::value, + int> = 0 > +void to_json(BasicJsonType& j, const T (&arr)[N]) { external_constructor<value_t::array>::construct(j, arr); } @@ -318,35 +325,12 @@ void to_json(BasicJsonType& j, const std::tuple<Args...>& t) struct to_json_fn { - private: template<typename BasicJsonType, typename T> - auto call(BasicJsonType& j, T&& val, priority_tag<1> /*unused*/) const noexcept(noexcept(to_json(j, std::forward<T>(val)))) + auto operator()(BasicJsonType& j, T&& val) const noexcept(noexcept(to_json(j, std::forward<T>(val)))) -> decltype(to_json(j, std::forward<T>(val)), void()) { return to_json(j, std::forward<T>(val)); } - - template<typename BasicJsonType, typename T> - void call(BasicJsonType& /*unused*/, T&& /*unused*/, priority_tag<0> /*unused*/) const noexcept - { - static_assert(sizeof(BasicJsonType) == 0, - "could not find to_json() method in T's namespace"); - -#ifdef _MSC_VER - // MSVC does not show a stacktrace for the above assert - using decayed = uncvref_t<T>; - static_assert(sizeof(typename decayed::force_msvc_stacktrace) == 0, - "forcing MSVC stacktrace to show which T we're talking about."); -#endif - } - - public: - template<typename BasicJsonType, typename T> - void operator()(BasicJsonType& j, T&& val) const - noexcept(noexcept(std::declval<to_json_fn>().call(j, std::forward<T>(val), priority_tag<1> {}))) - { - return call(j, std::forward<T>(val), priority_tag<1> {}); - } }; } diff --git a/include/nlohmann/detail/input/input_adapters.hpp b/include/nlohmann/detail/input/input_adapters.hpp index 01bec749..1ae77b5e 100644 --- a/include/nlohmann/detail/input/input_adapters.hpp +++ b/include/nlohmann/detail/input/input_adapters.hpp @@ -115,38 +115,66 @@ class input_buffer_adapter : public input_adapter_protocol const char* const limit; }; -template<typename WideStringType> -class wide_string_input_adapter : public input_adapter_protocol +template<typename WideStringType, size_t T> +struct wide_string_input_helper { - public: - explicit wide_string_input_adapter(const WideStringType& w) : str(w) {} - - std::char_traits<char>::int_type get_character() noexcept override + // UTF-32 + static void fill_buffer(const WideStringType& str, size_t& current_wchar, std::array<std::char_traits<char>::int_type, 4>& utf8_bytes, size_t& utf8_bytes_index, size_t& utf8_bytes_filled) { - // check if buffer needs to be filled - if (utf8_bytes_index == utf8_bytes_filled) + utf8_bytes_index = 0; + + if (current_wchar == str.size()) { - if (sizeof(typename WideStringType::value_type) == 2) + utf8_bytes[0] = std::char_traits<char>::eof(); + utf8_bytes_filled = 1; + } + else + { + // get the current character + const int wc = static_cast<int>(str[current_wchar++]); + + // UTF-32 to UTF-8 encoding + if (wc < 0x80) { - fill_buffer_utf16(); + utf8_bytes[0] = wc; + utf8_bytes_filled = 1; + } + else if (wc <= 0x7FF) + { + utf8_bytes[0] = 0xC0 | ((wc >> 6) & 0x1F); + utf8_bytes[1] = 0x80 | (wc & 0x3F); + utf8_bytes_filled = 2; + } + else if (wc <= 0xFFFF) + { + utf8_bytes[0] = 0xE0 | ((wc >> 12) & 0x0F); + utf8_bytes[1] = 0x80 | ((wc >> 6) & 0x3F); + utf8_bytes[2] = 0x80 | (wc & 0x3F); + utf8_bytes_filled = 3; + } + else if (wc <= 0x10FFFF) + { + utf8_bytes[0] = 0xF0 | ((wc >> 18) & 0x07); + utf8_bytes[1] = 0x80 | ((wc >> 12) & 0x3F); + utf8_bytes[2] = 0x80 | ((wc >> 6) & 0x3F); + utf8_bytes[3] = 0x80 | (wc & 0x3F); + utf8_bytes_filled = 4; } else { - fill_buffer_utf32(); + // unknown character + utf8_bytes[0] = wc; + utf8_bytes_filled = 1; } - - assert(utf8_bytes_filled > 0); - assert(utf8_bytes_index == 0); } - - // use buffer - assert(utf8_bytes_filled > 0); - assert(utf8_bytes_index < utf8_bytes_filled); - return utf8_bytes[utf8_bytes_index++]; } +}; - private: - void fill_buffer_utf16() +template<typename WideStringType> +struct wide_string_input_helper<WideStringType, 2> +{ + // UTF-16 + static void fill_buffer(const WideStringType& str, size_t& current_wchar, std::array<std::char_traits<char>::int_type, 4>& utf8_bytes, size_t& utf8_bytes_index, size_t& utf8_bytes_filled) { utf8_bytes_index = 0; @@ -201,58 +229,38 @@ class wide_string_input_adapter : public input_adapter_protocol } } } +}; - void fill_buffer_utf32() +template<typename WideStringType> +class wide_string_input_adapter : public input_adapter_protocol +{ + public: + explicit wide_string_input_adapter(const WideStringType& w) : str(w) {} + + std::char_traits<char>::int_type get_character() noexcept override { - utf8_bytes_index = 0; - - if (current_wchar == str.size()) + // check if buffer needs to be filled + if (utf8_bytes_index == utf8_bytes_filled) { - utf8_bytes[0] = std::char_traits<char>::eof(); - utf8_bytes_filled = 1; - } - else - { - // get the current character - const int wc = static_cast<int>(str[current_wchar++]); + fill_buffer<sizeof(typename WideStringType::value_type)>(); - // UTF-32 to UTF-8 encoding - if (wc < 0x80) - { - utf8_bytes[0] = wc; - utf8_bytes_filled = 1; - } - else if (wc <= 0x7FF) - { - utf8_bytes[0] = 0xC0 | ((wc >> 6) & 0x1F); - utf8_bytes[1] = 0x80 | (wc & 0x3F); - utf8_bytes_filled = 2; - } - else if (wc <= 0xFFFF) - { - utf8_bytes[0] = 0xE0 | ((wc >> 12) & 0x0F); - utf8_bytes[1] = 0x80 | ((wc >> 6) & 0x3F); - utf8_bytes[2] = 0x80 | (wc & 0x3F); - utf8_bytes_filled = 3; - } - else if (wc <= 0x10FFFF) - { - utf8_bytes[0] = 0xF0 | ((wc >> 18 ) & 0x07); - utf8_bytes[1] = 0x80 | ((wc >> 12) & 0x3F); - utf8_bytes[2] = 0x80 | ((wc >> 6) & 0x3F); - utf8_bytes[3] = 0x80 | (wc & 0x3F); - utf8_bytes_filled = 4; - } - else - { - // unknown character - utf8_bytes[0] = wc; - utf8_bytes_filled = 1; - } + assert(utf8_bytes_filled > 0); + assert(utf8_bytes_index == 0); } + + // use buffer + assert(utf8_bytes_filled > 0); + assert(utf8_bytes_index < utf8_bytes_filled); + return utf8_bytes[utf8_bytes_index++]; } private: + template<size_t T> + void fill_buffer() + { + wide_string_input_helper<WideStringType, T>::fill_buffer(str, current_wchar, utf8_bytes, utf8_bytes_index, utf8_bytes_filled); + } + /// the wstring to process const WideStringType& str; @@ -320,15 +328,18 @@ class input_adapter int>::type = 0> input_adapter(IteratorType first, IteratorType last) { +#ifndef NDEBUG // assertion to check that the iterator range is indeed contiguous, // see http://stackoverflow.com/a/35008842/266378 for more discussion - assert(std::accumulate( - first, last, std::pair<bool, int>(true, 0), - [&first](std::pair<bool, int> res, decltype(*first) val) + const auto is_contiguous = std::accumulate( + first, last, std::pair<bool, int>(true, 0), + [&first](std::pair<bool, int> res, decltype(*first) val) { res.first &= (val == *(std::next(std::addressof(*first), res.second++))); return res; - }).first); + }).first; + assert(is_contiguous); +#endif // assertion to check that each element is 1 byte long static_assert( diff --git a/include/nlohmann/detail/macro_scope.hpp b/include/nlohmann/detail/macro_scope.hpp index a5b6101e..06805b1a 100644 --- a/include/nlohmann/detail/macro_scope.hpp +++ b/include/nlohmann/detail/macro_scope.hpp @@ -10,7 +10,7 @@ #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" #endif #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) - #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900 + #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800 #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" #endif #endif @@ -62,6 +62,7 @@ #if defined(JSON_CATCH_USER) #undef JSON_CATCH #define JSON_CATCH JSON_CATCH_USER + #undef JSON_INTERNAL_CATCH #define JSON_INTERNAL_CATCH JSON_CATCH_USER #endif #if defined(JSON_INTERNAL_CATCH_USER) @@ -101,24 +102,3 @@ basic_json<ObjectType, ArrayType, StringType, BooleanType, \ NumberIntegerType, NumberUnsignedType, NumberFloatType, \ AllocatorType, JSONSerializer> - -/*! -@brief Helper to determine whether there's a key_type for T. - -This helper is used to tell associative containers apart from other containers -such as sequence containers. For instance, `std::map` passes the test as it -contains a `mapped_type`, whereas `std::vector` fails the test. - -@sa http://stackoverflow.com/a/7728728/266378 -@since version 1.0.0, overworked in version 2.0.6 -*/ -#define NLOHMANN_JSON_HAS_HELPER(type) \ - template<typename T> struct has_##type { \ - private: \ - template<typename U, typename = typename U::type> \ - static int detect(U &&); \ - static void detect(...); \ - public: \ - static constexpr bool value = \ - std::is_integral<decltype(detect(std::declval<T>()))>::value; \ - } diff --git a/include/nlohmann/detail/macro_unscope.hpp b/include/nlohmann/detail/macro_unscope.hpp index 032b1218..4c5aa915 100644 --- a/include/nlohmann/detail/macro_unscope.hpp +++ b/include/nlohmann/detail/macro_unscope.hpp @@ -20,4 +20,3 @@ #undef JSON_HAS_CPP_17 #undef NLOHMANN_BASIC_JSON_TPL_DECLARATION #undef NLOHMANN_BASIC_JSON_TPL -#undef NLOHMANN_JSON_HAS_HELPER diff --git a/include/nlohmann/detail/meta/cpp_future.hpp b/include/nlohmann/detail/meta/cpp_future.hpp index d12d6bdb..fa7478b8 100644 --- a/include/nlohmann/detail/meta/cpp_future.hpp +++ b/include/nlohmann/detail/meta/cpp_future.hpp @@ -46,26 +46,6 @@ template<> struct make_index_sequence<1> : index_sequence<0> {}; template<typename... Ts> using index_sequence_for = make_index_sequence<sizeof...(Ts)>; -/* -Implementation of two C++17 constructs: conjunction, negation. This is needed -to avoid evaluating all the traits in a condition - -For example: not std::is_same<void, T>::value and has_value_type<T>::value -will not compile when T = void (on MSVC at least). Whereas -conjunction<negation<std::is_same<void, T>>, has_value_type<T>>::value will -stop evaluating if negation<...>::value == false - -Please note that those constructs must be used with caution, since symbols can -become very long quickly (which can slow down compilation and cause MSVC -internal compiler errors). Only use it when you have to (see example ahead). -*/ -template<class...> struct conjunction : std::true_type {}; -template<class B1> struct conjunction<B1> : B1 {}; -template<class B1, class... Bn> -struct conjunction<B1, Bn...> : std::conditional<bool(B1::value), conjunction<Bn...>, B1>::type {}; - -template<class B> struct negation : std::integral_constant<bool, not B::value> {}; - // dispatch utility (taken from ranges-v3) template<unsigned N> struct priority_tag : priority_tag < N - 1 > {}; template<> struct priority_tag<0> {}; diff --git a/include/nlohmann/detail/meta/type_traits.hpp b/include/nlohmann/detail/meta/type_traits.hpp index caf81222..bb932ef6 100644 --- a/include/nlohmann/detail/meta/type_traits.hpp +++ b/include/nlohmann/detail/meta/type_traits.hpp @@ -7,6 +7,7 @@ #include <nlohmann/json_fwd.hpp> #include <nlohmann/detail/meta/cpp_future.hpp> +#include <nlohmann/detail/meta/detected.hpp> #include <nlohmann/detail/macro_scope.hpp> namespace nlohmann @@ -30,9 +31,64 @@ template<typename> struct is_basic_json : std::false_type {}; NLOHMANN_BASIC_JSON_TPL_DECLARATION struct is_basic_json<NLOHMANN_BASIC_JSON_TPL> : std::true_type {}; -//////////////////////// -// has_/is_ functions // -//////////////////////// +////////////////////////// +// aliases for detected // +////////////////////////// + +template <typename T> +using mapped_type_t = typename T::mapped_type; + +template <typename T> +using key_type_t = typename T::key_type; + +template <typename T> +using value_type_t = typename T::value_type; + +template <typename T> +using difference_type_t = typename T::difference_type; + +template <typename T> +using pointer_t = typename T::pointer; + +template <typename T> +using reference_t = typename T::reference; + +template <typename T> +using iterator_category_t = typename T::iterator_category; + +template <typename T> +using iterator_t = typename T::iterator; + +template <typename T, typename... Args> +using to_json_function = decltype(T::to_json(std::declval<Args>()...)); + +template <typename T, typename... Args> +using from_json_function = decltype(T::from_json(std::declval<Args>()...)); + +template <typename T, typename U> +using get_template_function = decltype(std::declval<T>().template get<U>()); + +/////////////////// +// is_ functions // +/////////////////// + +template <typename T, typename = void> +struct is_iterator_traits : std::false_type {}; + +template <typename T> +struct is_iterator_traits<std::iterator_traits<T>> +{ + private: + using traits = std::iterator_traits<T>; + + public: + static constexpr auto value = + is_detected<value_type_t, traits>::value && + is_detected<difference_type_t, traits>::value && + is_detected<pointer_t, traits>::value && + is_detected<iterator_category_t, traits>::value && + is_detected<reference_t, traits>::value; +}; // source: https://stackoverflow.com/a/37193089/4116453 @@ -42,165 +98,154 @@ struct is_complete_type : std::false_type {}; template <typename T> struct is_complete_type<T, decltype(void(sizeof(T)))> : std::true_type {}; -NLOHMANN_JSON_HAS_HELPER(mapped_type); -NLOHMANN_JSON_HAS_HELPER(key_type); -NLOHMANN_JSON_HAS_HELPER(value_type); -NLOHMANN_JSON_HAS_HELPER(iterator); - -template<bool B, class RealType, class CompatibleObjectType> +template <typename BasicJsonType, typename CompatibleObjectType, + typename = void> struct is_compatible_object_type_impl : std::false_type {}; -template<class RealType, class CompatibleObjectType> -struct is_compatible_object_type_impl<true, RealType, CompatibleObjectType> +template <typename BasicJsonType, typename CompatibleObjectType> +struct is_compatible_object_type_impl < + BasicJsonType, CompatibleObjectType, + enable_if_t<is_detected<mapped_type_t, CompatibleObjectType>::value and + is_detected<key_type_t, CompatibleObjectType>::value >> { - static constexpr auto value = - std::is_constructible<typename RealType::key_type, typename CompatibleObjectType::key_type>::value and - std::is_constructible<typename RealType::mapped_type, typename CompatibleObjectType::mapped_type>::value; + + using object_t = typename BasicJsonType::object_t; + + // macOS's is_constructible does not play well with nonesuch... + static constexpr bool value = + std::is_constructible<typename object_t::key_type, + typename CompatibleObjectType::key_type>::value and + std::is_constructible<typename object_t::mapped_type, + typename CompatibleObjectType::mapped_type>::value; }; -template<bool B, class RealType, class CompatibleStringType> +template <typename BasicJsonType, typename CompatibleObjectType> +struct is_compatible_object_type + : is_compatible_object_type_impl<BasicJsonType, CompatibleObjectType> {}; + +template <typename BasicJsonType, typename CompatibleStringType, + typename = void> struct is_compatible_string_type_impl : std::false_type {}; -template<class RealType, class CompatibleStringType> -struct is_compatible_string_type_impl<true, RealType, CompatibleStringType> +template <typename BasicJsonType, typename CompatibleStringType> +struct is_compatible_string_type_impl < + BasicJsonType, CompatibleStringType, + enable_if_t<is_detected_exact<typename BasicJsonType::string_t::value_type, + value_type_t, CompatibleStringType>::value >> { static constexpr auto value = - std::is_same<typename RealType::value_type, typename CompatibleStringType::value_type>::value and - std::is_constructible<RealType, CompatibleStringType>::value; + std::is_constructible<typename BasicJsonType::string_t, CompatibleStringType>::value; }; -template<class BasicJsonType, class CompatibleObjectType> -struct is_compatible_object_type -{ - static auto constexpr value = is_compatible_object_type_impl < - conjunction<negation<std::is_same<void, CompatibleObjectType>>, - has_mapped_type<CompatibleObjectType>, - has_key_type<CompatibleObjectType>>::value, - typename BasicJsonType::object_t, CompatibleObjectType >::value; -}; - -template<class BasicJsonType, class CompatibleStringType> +template <typename BasicJsonType, typename CompatibleStringType> struct is_compatible_string_type + : is_compatible_string_type_impl<BasicJsonType, CompatibleStringType> {}; + +template <typename BasicJsonType, typename CompatibleArrayType, typename = void> +struct is_compatible_array_type_impl : std::false_type {}; + +template <typename BasicJsonType, typename CompatibleArrayType> +struct is_compatible_array_type_impl < + BasicJsonType, CompatibleArrayType, + enable_if_t<is_detected<value_type_t, CompatibleArrayType>::value and + is_detected<iterator_t, CompatibleArrayType>::value >> { - static auto constexpr value = is_compatible_string_type_impl < - conjunction<negation<std::is_same<void, CompatibleStringType>>, - has_value_type<CompatibleStringType>>::value, - typename BasicJsonType::string_t, CompatibleStringType >::value; + // This is needed because json_reverse_iterator has a ::iterator type... + // Therefore it is detected as a CompatibleArrayType. + // The real fix would be to have an Iterable concept. + static constexpr bool value = not is_iterator_traits<std::iterator_traits<CompatibleArrayType>>::value; }; -template<typename BasicJsonType, typename T> -struct is_basic_json_nested_type -{ - static auto constexpr value = std::is_same<T, typename BasicJsonType::iterator>::value or - std::is_same<T, typename BasicJsonType::const_iterator>::value or - std::is_same<T, typename BasicJsonType::reverse_iterator>::value or - std::is_same<T, typename BasicJsonType::const_reverse_iterator>::value; -}; - -template<class BasicJsonType, class CompatibleArrayType> +template <typename BasicJsonType, typename CompatibleArrayType> struct is_compatible_array_type -{ - static auto constexpr value = - conjunction<negation<std::is_same<void, CompatibleArrayType>>, - negation<is_compatible_object_type< - BasicJsonType, CompatibleArrayType>>, - negation<std::is_constructible<typename BasicJsonType::string_t, - CompatibleArrayType>>, - negation<is_basic_json_nested_type<BasicJsonType, CompatibleArrayType>>, - has_value_type<CompatibleArrayType>, - has_iterator<CompatibleArrayType>>::value; -}; + : is_compatible_array_type_impl<BasicJsonType, CompatibleArrayType> {}; -template<bool, typename, typename> +template <typename RealIntegerType, typename CompatibleNumberIntegerType, + typename = void> struct is_compatible_integer_type_impl : std::false_type {}; -template<typename RealIntegerType, typename CompatibleNumberIntegerType> -struct is_compatible_integer_type_impl<true, RealIntegerType, CompatibleNumberIntegerType> +template <typename RealIntegerType, typename CompatibleNumberIntegerType> +struct is_compatible_integer_type_impl < + RealIntegerType, CompatibleNumberIntegerType, + enable_if_t<std::is_integral<RealIntegerType>::value and + std::is_integral<CompatibleNumberIntegerType>::value and + not std::is_same<bool, CompatibleNumberIntegerType>::value >> { // is there an assert somewhere on overflows? using RealLimits = std::numeric_limits<RealIntegerType>; using CompatibleLimits = std::numeric_limits<CompatibleNumberIntegerType>; static constexpr auto value = - std::is_constructible<RealIntegerType, CompatibleNumberIntegerType>::value and + std::is_constructible<RealIntegerType, + CompatibleNumberIntegerType>::value and CompatibleLimits::is_integer and RealLimits::is_signed == CompatibleLimits::is_signed; }; -template<typename RealIntegerType, typename CompatibleNumberIntegerType> +template <typename RealIntegerType, typename CompatibleNumberIntegerType> struct is_compatible_integer_type -{ - static constexpr auto value = - is_compatible_integer_type_impl < - std::is_integral<CompatibleNumberIntegerType>::value and - not std::is_same<bool, CompatibleNumberIntegerType>::value, - RealIntegerType, CompatibleNumberIntegerType > ::value; -}; + : is_compatible_integer_type_impl<RealIntegerType, + CompatibleNumberIntegerType> {}; // trait checking if JSONSerializer<T>::from_json(json const&, udt&) exists -template<typename BasicJsonType, typename T> -struct has_from_json -{ - private: - // also check the return type of from_json - template<typename U, typename = enable_if_t<std::is_same<void, decltype(uncvref_t<U>::from_json( - std::declval<BasicJsonType>(), std::declval<T&>()))>::value>> - static int detect(U&&); - static void detect(...); +template <typename BasicJsonType, typename T, typename = void> +struct has_from_json : std::false_type {}; - public: - static constexpr bool value = std::is_integral<decltype( - detect(std::declval<typename BasicJsonType::template json_serializer<T, void>>()))>::value; +template <typename BasicJsonType, typename T> +struct has_from_json<BasicJsonType, T, + enable_if_t<not is_basic_json<T>::value>> +{ + using serializer = typename BasicJsonType::template json_serializer<T, void>; + + static constexpr bool value = + is_detected_exact<void, from_json_function, serializer, + const BasicJsonType&, T&>::value; }; // This trait checks if JSONSerializer<T>::from_json(json const&) exists // this overload is used for non-default-constructible user-defined-types -template<typename BasicJsonType, typename T> -struct has_non_default_from_json -{ - private: - template < - typename U, - typename = enable_if_t<std::is_same< - T, decltype(uncvref_t<U>::from_json(std::declval<BasicJsonType>()))>::value >> - static int detect(U&&); - static void detect(...); +template <typename BasicJsonType, typename T, typename = void> +struct has_non_default_from_json : std::false_type {}; - public: - static constexpr bool value = std::is_integral<decltype(detect( - std::declval<typename BasicJsonType::template json_serializer<T, void>>()))>::value; +template<typename BasicJsonType, typename T> +struct has_non_default_from_json<BasicJsonType, T, enable_if_t<not is_basic_json<T>::value>> +{ + using serializer = typename BasicJsonType::template json_serializer<T, void>; + + static constexpr bool value = + is_detected_exact<T, from_json_function, serializer, + const BasicJsonType&>::value; }; // This trait checks if BasicJsonType::json_serializer<T>::to_json exists -template<typename BasicJsonType, typename T> -struct has_to_json -{ - private: - template<typename U, typename = decltype(uncvref_t<U>::to_json( - std::declval<BasicJsonType&>(), std::declval<T>()))> - static int detect(U&&); - static void detect(...); +// Do not evaluate the trait when T is a basic_json type, to avoid template instantiation infinite recursion. +template <typename BasicJsonType, typename T, typename = void> +struct has_to_json : std::false_type {}; - public: - static constexpr bool value = std::is_integral<decltype(detect( - std::declval<typename BasicJsonType::template json_serializer<T, void>>()))>::value; +template <typename BasicJsonType, typename T> +struct has_to_json<BasicJsonType, T, enable_if_t<not is_basic_json<T>::value>> +{ + using serializer = typename BasicJsonType::template json_serializer<T, void>; + + static constexpr bool value = + is_detected_exact<void, to_json_function, serializer, BasicJsonType&, + T>::value; }; -template <typename BasicJsonType, typename CompatibleCompleteType> -struct is_compatible_complete_type +template <typename BasicJsonType, typename CompatibleType, typename = void> +struct is_compatible_type_impl: std::false_type {}; + +template <typename BasicJsonType, typename CompatibleType> +struct is_compatible_type_impl < + BasicJsonType, CompatibleType, + enable_if_t<is_complete_type<CompatibleType>::value >> { static constexpr bool value = - not std::is_base_of<std::istream, CompatibleCompleteType>::value and - not is_basic_json<CompatibleCompleteType>::value and - not is_basic_json_nested_type<BasicJsonType, CompatibleCompleteType>::value and - has_to_json<BasicJsonType, CompatibleCompleteType>::value; + has_to_json<BasicJsonType, CompatibleType>::value; }; template <typename BasicJsonType, typename CompatibleType> struct is_compatible_type - : conjunction<is_complete_type<CompatibleType>, - is_compatible_complete_type<BasicJsonType, CompatibleType>> -{ -}; + : is_compatible_type_impl<BasicJsonType, CompatibleType> {}; } } diff --git a/include/nlohmann/detail/meta/void_t.hpp b/include/nlohmann/detail/meta/void_t.hpp index 66c4a359..2528ea84 100644 --- a/include/nlohmann/detail/meta/void_t.hpp +++ b/include/nlohmann/detail/meta/void_t.hpp @@ -4,7 +4,10 @@ namespace nlohmann { namespace detail { -template <typename...> -using void_t = void; +template <typename ...Ts> struct make_void +{ + using type = void; +}; +template <typename ...Ts> using void_t = typename make_void<Ts...>::type; } } diff --git a/include/nlohmann/detail/output/serializer.hpp b/include/nlohmann/detail/output/serializer.hpp index de3676ac..e2655f04 100644 --- a/include/nlohmann/detail/output/serializer.hpp +++ b/include/nlohmann/detail/output/serializer.hpp @@ -442,7 +442,7 @@ class serializer return; } - const bool is_negative = (x <= 0) and (x != 0); // see issue #755 + const bool is_negative = not (x >= 0); // see issue #755 std::size_t i = 0; while (x != 0) diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index 1f39e3ec..52c301cf 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License <http://opensource.org/licenses/MIT>. @@ -31,7 +31,7 @@ SOFTWARE. #define NLOHMANN_JSON_HPP #define NLOHMANN_JSON_VERSION_MAJOR 3 -#define NLOHMANN_JSON_VERSION_MINOR 2 +#define NLOHMANN_JSON_VERSION_MINOR 3 #define NLOHMANN_JSON_VERSION_PATCH 0 #include <algorithm> // all_of, find, for_each @@ -947,7 +947,7 @@ class basic_json object = nullptr; // silence warning, see #821 if (JSON_UNLIKELY(t == value_t::null)) { - JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.2.0")); // LCOV_EXCL_LINE + JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.3.0")); // LCOV_EXCL_LINE } break; } @@ -1243,7 +1243,7 @@ class basic_json template <typename CompatibleType, typename U = detail::uncvref_t<CompatibleType>, detail::enable_if_t< - detail::is_compatible_type<basic_json_t, U>::value, int> = 0> + not detail::is_basic_json<U>::value and detail::is_compatible_type<basic_json_t, U>::value, int> = 0> basic_json(CompatibleType && val) noexcept(noexcept( JSONSerializer<U>::to_json(std::declval<basic_json_t&>(), std::forward<CompatibleType>(val)))) @@ -2624,51 +2624,50 @@ class basic_json } /*! - @brief get a pointer value (explicit) + @brief get a value (explicit) - Explicit pointer access to the internally stored JSON value. No copies are - made. + Explicit type conversion between the JSON value and a compatible value. + The value is filled into the input parameter by calling the @ref json_serializer<ValueType> + `from_json()` method. - @warning The pointer becomes invalid if the underlying JSON object - changes. + The function is equivalent to executing + @code {.cpp} + ValueType v; + JSONSerializer<ValueType>::from_json(*this, v); + @endcode - @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref - object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, - @ref number_unsigned_t, or @ref number_float_t. + This overloads is chosen if: + - @a ValueType is not @ref basic_json, + - @ref json_serializer<ValueType> has a `from_json()` method of the form + `void from_json(const basic_json&, ValueType&)`, and - @return pointer to the internally stored JSON value if the requested - pointer type @a PointerType fits to the JSON value; `nullptr` otherwise + @tparam ValueType the input parameter type. - @complexity Constant. + @return the input parameter, allowing chaining calls. - @liveexample{The example below shows how pointers to internal values of a - JSON value can be requested. Note that no type conversions are made and a - `nullptr` is returned if the value and the requested pointer type does not - match.,get__PointerType} + @throw what @ref json_serializer<ValueType> `from_json()` method throws - @sa @ref get_ptr() for explicit pointer-member access + @liveexample{The example below shows several conversions from JSON values + to other types. There a few things to note: (1) Floating-point numbers can + be converted to integers\, (2) A JSON array can be converted to a standard + `std::vector<short>`\, (3) A JSON object can be converted to C++ + associative containers such as `std::unordered_map<std::string\, + json>`.,get_to} - @since version 1.0.0 + @since version 3.3.0 */ - template<typename PointerType, typename std::enable_if< - std::is_pointer<PointerType>::value, int>::type = 0> - PointerType get() noexcept + template<typename ValueType, + detail::enable_if_t < + not detail::is_basic_json<ValueType>::value and + detail::has_from_json<basic_json_t, ValueType>::value, + int> = 0> + ValueType & get_to(ValueType& v) const noexcept(noexcept( + JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>(), v))) { - // delegate the call to get_ptr - return get_ptr<PointerType>(); + JSONSerializer<ValueType>::from_json(*this, v); + return v; } - /*! - @brief get a pointer value (explicit) - @copydoc get() - */ - template<typename PointerType, typename std::enable_if< - std::is_pointer<PointerType>::value, int>::type = 0> - constexpr const PointerType get() const noexcept - { - // delegate the call to get_ptr - return get_ptr<PointerType>(); - } /*! @brief get a pointer value (implicit) @@ -2698,23 +2697,8 @@ class basic_json */ template<typename PointerType, typename std::enable_if< std::is_pointer<PointerType>::value, int>::type = 0> - PointerType get_ptr() noexcept + auto get_ptr() noexcept -> decltype(std::declval<basic_json_t&>().get_impl_ptr(std::declval<PointerType>())) { - // get the type of the PointerType (remove pointer and const) - using pointee_t = typename std::remove_const<typename - std::remove_pointer<typename - std::remove_const<PointerType>::type>::type>::type; - // make sure the type matches the allowed types - static_assert( - std::is_same<object_t, pointee_t>::value - or std::is_same<array_t, pointee_t>::value - or std::is_same<string_t, pointee_t>::value - or std::is_same<boolean_t, pointee_t>::value - or std::is_same<number_integer_t, pointee_t>::value - or std::is_same<number_unsigned_t, pointee_t>::value - or std::is_same<number_float_t, pointee_t>::value - , "incompatible pointer type"); - // delegate the call to get_impl_ptr<>() return get_impl_ptr(static_cast<PointerType>(nullptr)); } @@ -2726,27 +2710,59 @@ class basic_json template<typename PointerType, typename std::enable_if< std::is_pointer<PointerType>::value and std::is_const<typename std::remove_pointer<PointerType>::type>::value, int>::type = 0> - constexpr const PointerType get_ptr() const noexcept + constexpr auto get_ptr() const noexcept -> decltype(std::declval<const basic_json_t&>().get_impl_ptr(std::declval<PointerType>())) { - // get the type of the PointerType (remove pointer and const) - using pointee_t = typename std::remove_const<typename - std::remove_pointer<typename - std::remove_const<PointerType>::type>::type>::type; - // make sure the type matches the allowed types - static_assert( - std::is_same<object_t, pointee_t>::value - or std::is_same<array_t, pointee_t>::value - or std::is_same<string_t, pointee_t>::value - or std::is_same<boolean_t, pointee_t>::value - or std::is_same<number_integer_t, pointee_t>::value - or std::is_same<number_unsigned_t, pointee_t>::value - or std::is_same<number_float_t, pointee_t>::value - , "incompatible pointer type"); - // delegate the call to get_impl_ptr<>() const return get_impl_ptr(static_cast<PointerType>(nullptr)); } + /*! + @brief get a pointer value (explicit) + + Explicit pointer access to the internally stored JSON value. No copies are + made. + + @warning The pointer becomes invalid if the underlying JSON object + changes. + + @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref + object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, + @ref number_unsigned_t, or @ref number_float_t. + + @return pointer to the internally stored JSON value if the requested + pointer type @a PointerType fits to the JSON value; `nullptr` otherwise + + @complexity Constant. + + @liveexample{The example below shows how pointers to internal values of a + JSON value can be requested. Note that no type conversions are made and a + `nullptr` is returned if the value and the requested pointer type does not + match.,get__PointerType} + + @sa @ref get_ptr() for explicit pointer-member access + + @since version 1.0.0 + */ + template<typename PointerType, typename std::enable_if< + std::is_pointer<PointerType>::value, int>::type = 0> + auto get() noexcept -> decltype(std::declval<basic_json_t&>().template get_ptr<PointerType>()) + { + // delegate the call to get_ptr + return get_ptr<PointerType>(); + } + + /*! + @brief get a pointer value (explicit) + @copydoc get() + */ + template<typename PointerType, typename std::enable_if< + std::is_pointer<PointerType>::value, int>::type = 0> + constexpr auto get() const noexcept -> decltype(std::declval<const basic_json_t&>().template get_ptr<PointerType>()) + { + // delegate the call to get_ptr + return get_ptr<PointerType>(); + } + /*! @brief get a reference value (implicit) @@ -2828,12 +2844,14 @@ class basic_json not std::is_same<ValueType, detail::json_ref<basic_json>>::value and not std::is_same<ValueType, typename string_t::value_type>::value and not detail::is_basic_json<ValueType>::value + #ifndef _MSC_VER // fix for issue #167 operator<< ambiguity under VS2015 and not std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value #if defined(JSON_HAS_CPP_17) && defined(_MSC_VER) and _MSC_VER <= 1914 and not 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 , int >::type = 0 > operator ValueType() const { @@ -3097,7 +3115,7 @@ class basic_json return m_value.array->operator[](idx); } - JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); + JSON_THROW(type_error::create(305, "cannot use operator[] with a numeric argument with " + std::string(type_name()))); } /*! @@ -3127,7 +3145,7 @@ class basic_json return m_value.array->operator[](idx); } - JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); + JSON_THROW(type_error::create(305, "cannot use operator[] with a numeric argument with " + std::string(type_name()))); } /*! @@ -3173,7 +3191,7 @@ class basic_json return m_value.object->operator[](key); } - JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); + JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()))); } /*! @@ -3215,7 +3233,7 @@ class basic_json return m_value.object->find(key)->second; } - JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); + JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()))); } /*! @@ -3262,7 +3280,7 @@ class basic_json return m_value.object->operator[](key); } - JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); + JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()))); } /*! @@ -3305,7 +3323,7 @@ class basic_json return m_value.object->find(key)->second; } - JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); + JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()))); } /*! @@ -4943,6 +4961,26 @@ class basic_json return {it, res.second}; } + /// Helper for insertion of an iterator + /// @note: This uses std::distance to support GCC 4.8, + /// see https://github.com/nlohmann/json/pull/1257 + template<typename... Args> + iterator insert_iterator(const_iterator pos, Args&& ... args) + { + iterator result(this); + assert(m_value.array != nullptr); + + 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)...); + result.m_it.array_iterator = m_value.array->begin() + insert_pos; + + // This could have been written as: + // result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val); + // but the return value of insert is missing in GCC 4.8, so it is written this way instead. + + return result; + } + /*! @brief inserts element @@ -4977,9 +5015,7 @@ class basic_json } // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, val); - return result; + return insert_iterator(pos, val); } JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); @@ -5030,9 +5066,7 @@ class basic_json } // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val); - return result; + return insert_iterator(pos, cnt, val); } JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); @@ -5094,12 +5128,7 @@ class basic_json } // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert( - pos.m_it.array_iterator, - first.m_it.array_iterator, - last.m_it.array_iterator); - return result; + return insert_iterator(pos, first.m_it.array_iterator, last.m_it.array_iterator); } /*! @@ -5141,9 +5170,7 @@ class basic_json } // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, ilist.begin(), ilist.end()); - return result; + return insert_iterator(pos, ilist.begin(), ilist.end()); } /*! @@ -7691,19 +7718,6 @@ class basic_json // specialization of std::swap, and std::hash namespace std { -/*! -@brief exchanges the values of two JSON objects - -@since version 1.0.0 -*/ -template<> -inline void swap<nlohmann::json>(nlohmann::json& j1, nlohmann::json& j2) noexcept( - is_nothrow_move_constructible<nlohmann::json>::value and - is_nothrow_move_assignable<nlohmann::json>::value -) -{ - j1.swap(j2); -} /// hash value for JSON objects template<> @@ -7739,6 +7753,20 @@ struct less< ::nlohmann::detail::value_t> } }; +/*! +@brief exchanges the values of two JSON objects + +@since version 1.0.0 +*/ +template<> +inline void swap<nlohmann::json>(nlohmann::json& j1, nlohmann::json& j2) noexcept( + is_nothrow_move_constructible<nlohmann::json>::value and + is_nothrow_move_assignable<nlohmann::json>::value +) +{ + j1.swap(j2); +} + } // namespace std /*! diff --git a/meson.build b/meson.build index c79dcd3e..6935567b 100644 --- a/meson.build +++ b/meson.build @@ -1,9 +1,13 @@ -project('nlohmann_json', 'cpp') +project('nlohmann_json', + 'cpp', + version : '3.3.0', + license : 'MIT', +) nlohmann_json_dep = declare_dependency( - include_directories: include_directories('single_include') + include_directories: include_directories('single_include') ) nlohmann_json_multiple_headers = declare_dependency( - include_directories: include_directories('include') + include_directories: include_directories('include') ) diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index b80386f3..c40620ad 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License <http://opensource.org/licenses/MIT>. @@ -31,7 +31,7 @@ SOFTWARE. #define NLOHMANN_JSON_HPP #define NLOHMANN_JSON_VERSION_MAJOR 3 -#define NLOHMANN_JSON_VERSION_MINOR 2 +#define NLOHMANN_JSON_VERSION_MINOR 3 #define NLOHMANN_JSON_VERSION_PATCH 0 #include <algorithm> // all_of, find, for_each @@ -125,7 +125,7 @@ using json = basic_json<>; #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" #endif #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) - #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900 + #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800 #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" #endif #endif @@ -177,6 +177,7 @@ using json = basic_json<>; #if defined(JSON_CATCH_USER) #undef JSON_CATCH #define JSON_CATCH JSON_CATCH_USER + #undef JSON_INTERNAL_CATCH #define JSON_INTERNAL_CATCH JSON_CATCH_USER #endif #if defined(JSON_INTERNAL_CATCH_USER) @@ -217,27 +218,6 @@ using json = basic_json<>; NumberIntegerType, NumberUnsignedType, NumberFloatType, \ AllocatorType, JSONSerializer> -/*! -@brief Helper to determine whether there's a key_type for T. - -This helper is used to tell associative containers apart from other containers -such as sequence containers. For instance, `std::map` passes the test as it -contains a `mapped_type`, whereas `std::vector` fails the test. - -@sa http://stackoverflow.com/a/7728728/266378 -@since version 1.0.0, overworked in version 2.0.6 -*/ -#define NLOHMANN_JSON_HAS_HELPER(type) \ - template<typename T> struct has_##type { \ - private: \ - template<typename U, typename = typename U::type> \ - static int detect(U &&); \ - static void detect(...); \ - public: \ - static constexpr bool value = \ - std::is_integral<decltype(detect(std::declval<T>()))>::value; \ - } - // #include <nlohmann/detail/meta/cpp_future.hpp> @@ -287,26 +267,6 @@ template<> struct make_index_sequence<1> : index_sequence<0> {}; template<typename... Ts> using index_sequence_for = make_index_sequence<sizeof...(Ts)>; -/* -Implementation of two C++17 constructs: conjunction, negation. This is needed -to avoid evaluating all the traits in a condition - -For example: not std::is_same<void, T>::value and has_value_type<T>::value -will not compile when T = void (on MSVC at least). Whereas -conjunction<negation<std::is_same<void, T>>, has_value_type<T>>::value will -stop evaluating if negation<...>::value == false - -Please note that those constructs must be used with caution, since symbols can -become very long quickly (which can slow down compilation and cause MSVC -internal compiler errors). Only use it when you have to (see example ahead). -*/ -template<class...> struct conjunction : std::true_type {}; -template<class B1> struct conjunction<B1> : B1 {}; -template<class B1, class... Bn> -struct conjunction<B1, Bn...> : std::conditional<bool(B1::value), conjunction<Bn...>, B1>::type {}; - -template<class B> struct negation : std::integral_constant<bool, not B::value> {}; - // dispatch utility (taken from ranges-v3) template<unsigned N> struct priority_tag : priority_tag < N - 1 > {}; template<> struct priority_tag<0> {}; @@ -335,6 +295,78 @@ constexpr T static_const<T>::value; // #include <nlohmann/detail/meta/cpp_future.hpp> +// #include <nlohmann/detail/meta/detected.hpp> + + +#include <type_traits> + +// #include <nlohmann/detail/meta/void_t.hpp> + + +namespace nlohmann +{ +namespace detail +{ +template <typename ...Ts> struct make_void +{ + using type = void; +}; +template <typename ...Ts> using void_t = typename make_void<Ts...>::type; +} +} + + +// http://en.cppreference.com/w/cpp/experimental/is_detected +namespace nlohmann +{ +namespace detail +{ +struct nonesuch +{ + nonesuch() = delete; + ~nonesuch() = delete; + nonesuch(nonesuch const&) = delete; + void operator=(nonesuch const&) = delete; +}; + +template <class Default, + class AlwaysVoid, + template <class...> class Op, + class... Args> +struct detector +{ + using value_t = std::false_type; + using type = Default; +}; + +template <class Default, template <class...> class Op, class... Args> +struct detector<Default, void_t<Op<Args...>>, Op, Args...> +{ + using value_t = std::true_type; + using type = Op<Args...>; +}; + +template <template <class...> class Op, class... Args> +using is_detected = typename detector<nonesuch, void, Op, Args...>::value_t; + +template <template <class...> class Op, class... Args> +using detected_t = typename detector<nonesuch, void, Op, Args...>::type; + +template <class Default, template <class...> class Op, class... Args> +using detected_or = detector<Default, void, Op, Args...>; + +template <class Default, template <class...> class Op, class... Args> +using detected_or_t = typename detected_or<Default, Op, Args...>::type; + +template <class Expected, template <class...> class Op, class... Args> +using is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>; + +template <class To, template <class...> class Op, class... Args> +using is_detected_convertible = + std::is_convertible<detected_t<Op, Args...>, To>; +} +} + // #include <nlohmann/detail/macro_scope.hpp> @@ -359,9 +391,64 @@ template<typename> struct is_basic_json : std::false_type {}; NLOHMANN_BASIC_JSON_TPL_DECLARATION struct is_basic_json<NLOHMANN_BASIC_JSON_TPL> : std::true_type {}; -//////////////////////// -// has_/is_ functions // -//////////////////////// +////////////////////////// +// aliases for detected // +////////////////////////// + +template <typename T> +using mapped_type_t = typename T::mapped_type; + +template <typename T> +using key_type_t = typename T::key_type; + +template <typename T> +using value_type_t = typename T::value_type; + +template <typename T> +using difference_type_t = typename T::difference_type; + +template <typename T> +using pointer_t = typename T::pointer; + +template <typename T> +using reference_t = typename T::reference; + +template <typename T> +using iterator_category_t = typename T::iterator_category; + +template <typename T> +using iterator_t = typename T::iterator; + +template <typename T, typename... Args> +using to_json_function = decltype(T::to_json(std::declval<Args>()...)); + +template <typename T, typename... Args> +using from_json_function = decltype(T::from_json(std::declval<Args>()...)); + +template <typename T, typename U> +using get_template_function = decltype(std::declval<T>().template get<U>()); + +/////////////////// +// is_ functions // +/////////////////// + +template <typename T, typename = void> +struct is_iterator_traits : std::false_type {}; + +template <typename T> +struct is_iterator_traits<std::iterator_traits<T>> +{ + private: + using traits = std::iterator_traits<T>; + + public: + static constexpr auto value = + is_detected<value_type_t, traits>::value && + is_detected<difference_type_t, traits>::value && + is_detected<pointer_t, traits>::value && + is_detected<iterator_category_t, traits>::value && + is_detected<reference_t, traits>::value; +}; // source: https://stackoverflow.com/a/37193089/4116453 @@ -371,166 +458,155 @@ struct is_complete_type : std::false_type {}; template <typename T> struct is_complete_type<T, decltype(void(sizeof(T)))> : std::true_type {}; -NLOHMANN_JSON_HAS_HELPER(mapped_type); -NLOHMANN_JSON_HAS_HELPER(key_type); -NLOHMANN_JSON_HAS_HELPER(value_type); -NLOHMANN_JSON_HAS_HELPER(iterator); - -template<bool B, class RealType, class CompatibleObjectType> +template <typename BasicJsonType, typename CompatibleObjectType, + typename = void> struct is_compatible_object_type_impl : std::false_type {}; -template<class RealType, class CompatibleObjectType> -struct is_compatible_object_type_impl<true, RealType, CompatibleObjectType> +template <typename BasicJsonType, typename CompatibleObjectType> +struct is_compatible_object_type_impl < + BasicJsonType, CompatibleObjectType, + enable_if_t<is_detected<mapped_type_t, CompatibleObjectType>::value and + is_detected<key_type_t, CompatibleObjectType>::value >> { - static constexpr auto value = - std::is_constructible<typename RealType::key_type, typename CompatibleObjectType::key_type>::value and - std::is_constructible<typename RealType::mapped_type, typename CompatibleObjectType::mapped_type>::value; + + using object_t = typename BasicJsonType::object_t; + + // macOS's is_constructible does not play well with nonesuch... + static constexpr bool value = + std::is_constructible<typename object_t::key_type, + typename CompatibleObjectType::key_type>::value and + std::is_constructible<typename object_t::mapped_type, + typename CompatibleObjectType::mapped_type>::value; }; -template<bool B, class RealType, class CompatibleStringType> +template <typename BasicJsonType, typename CompatibleObjectType> +struct is_compatible_object_type + : is_compatible_object_type_impl<BasicJsonType, CompatibleObjectType> {}; + +template <typename BasicJsonType, typename CompatibleStringType, + typename = void> struct is_compatible_string_type_impl : std::false_type {}; -template<class RealType, class CompatibleStringType> -struct is_compatible_string_type_impl<true, RealType, CompatibleStringType> +template <typename BasicJsonType, typename CompatibleStringType> +struct is_compatible_string_type_impl < + BasicJsonType, CompatibleStringType, + enable_if_t<is_detected_exact<typename BasicJsonType::string_t::value_type, + value_type_t, CompatibleStringType>::value >> { static constexpr auto value = - std::is_same<typename RealType::value_type, typename CompatibleStringType::value_type>::value and - std::is_constructible<RealType, CompatibleStringType>::value; + std::is_constructible<typename BasicJsonType::string_t, CompatibleStringType>::value; }; -template<class BasicJsonType, class CompatibleObjectType> -struct is_compatible_object_type -{ - static auto constexpr value = is_compatible_object_type_impl < - conjunction<negation<std::is_same<void, CompatibleObjectType>>, - has_mapped_type<CompatibleObjectType>, - has_key_type<CompatibleObjectType>>::value, - typename BasicJsonType::object_t, CompatibleObjectType >::value; -}; - -template<class BasicJsonType, class CompatibleStringType> +template <typename BasicJsonType, typename CompatibleStringType> struct is_compatible_string_type + : is_compatible_string_type_impl<BasicJsonType, CompatibleStringType> {}; + +template <typename BasicJsonType, typename CompatibleArrayType, typename = void> +struct is_compatible_array_type_impl : std::false_type {}; + +template <typename BasicJsonType, typename CompatibleArrayType> +struct is_compatible_array_type_impl < + BasicJsonType, CompatibleArrayType, + enable_if_t<is_detected<value_type_t, CompatibleArrayType>::value and + is_detected<iterator_t, CompatibleArrayType>::value >> { - static auto constexpr value = is_compatible_string_type_impl < - conjunction<negation<std::is_same<void, CompatibleStringType>>, - has_value_type<CompatibleStringType>>::value, - typename BasicJsonType::string_t, CompatibleStringType >::value; + // This is needed because json_reverse_iterator has a ::iterator type... + // Therefore it is detected as a CompatibleArrayType. + // The real fix would be to have an Iterable concept. + static constexpr bool value = not is_iterator_traits<std::iterator_traits<CompatibleArrayType>>::value; }; -template<typename BasicJsonType, typename T> -struct is_basic_json_nested_type -{ - static auto constexpr value = std::is_same<T, typename BasicJsonType::iterator>::value or - std::is_same<T, typename BasicJsonType::const_iterator>::value or - std::is_same<T, typename BasicJsonType::reverse_iterator>::value or - std::is_same<T, typename BasicJsonType::const_reverse_iterator>::value; -}; - -template<class BasicJsonType, class CompatibleArrayType> +template <typename BasicJsonType, typename CompatibleArrayType> struct is_compatible_array_type -{ - static auto constexpr value = - conjunction<negation<std::is_same<void, CompatibleArrayType>>, - negation<is_compatible_object_type< - BasicJsonType, CompatibleArrayType>>, - negation<std::is_constructible<typename BasicJsonType::string_t, - CompatibleArrayType>>, - negation<is_basic_json_nested_type<BasicJsonType, CompatibleArrayType>>, - has_value_type<CompatibleArrayType>, - has_iterator<CompatibleArrayType>>::value; -}; + : is_compatible_array_type_impl<BasicJsonType, CompatibleArrayType> {}; -template<bool, typename, typename> +template <typename RealIntegerType, typename CompatibleNumberIntegerType, + typename = void> struct is_compatible_integer_type_impl : std::false_type {}; -template<typename RealIntegerType, typename CompatibleNumberIntegerType> -struct is_compatible_integer_type_impl<true, RealIntegerType, CompatibleNumberIntegerType> +template <typename RealIntegerType, typename CompatibleNumberIntegerType> +struct is_compatible_integer_type_impl < + RealIntegerType, CompatibleNumberIntegerType, + enable_if_t<std::is_integral<RealIntegerType>::value and + std::is_integral<CompatibleNumberIntegerType>::value and + not std::is_same<bool, CompatibleNumberIntegerType>::value >> { // is there an assert somewhere on overflows? using RealLimits = std::numeric_limits<RealIntegerType>; using CompatibleLimits = std::numeric_limits<CompatibleNumberIntegerType>; static constexpr auto value = - std::is_constructible<RealIntegerType, CompatibleNumberIntegerType>::value and + std::is_constructible<RealIntegerType, + CompatibleNumberIntegerType>::value and CompatibleLimits::is_integer and RealLimits::is_signed == CompatibleLimits::is_signed; }; -template<typename RealIntegerType, typename CompatibleNumberIntegerType> +template <typename RealIntegerType, typename CompatibleNumberIntegerType> struct is_compatible_integer_type -{ - static constexpr auto value = - is_compatible_integer_type_impl < - std::is_integral<CompatibleNumberIntegerType>::value and - not std::is_same<bool, CompatibleNumberIntegerType>::value, - RealIntegerType, CompatibleNumberIntegerType > ::value; -}; + : is_compatible_integer_type_impl<RealIntegerType, + CompatibleNumberIntegerType> {}; // trait checking if JSONSerializer<T>::from_json(json const&, udt&) exists -template<typename BasicJsonType, typename T> -struct has_from_json -{ - private: - // also check the return type of from_json - template<typename U, typename = enable_if_t<std::is_same<void, decltype(uncvref_t<U>::from_json( - std::declval<BasicJsonType>(), std::declval<T&>()))>::value>> - static int detect(U&&); - static void detect(...); +template <typename BasicJsonType, typename T, typename = void> +struct has_from_json : std::false_type {}; - public: - static constexpr bool value = std::is_integral<decltype( - detect(std::declval<typename BasicJsonType::template json_serializer<T, void>>()))>::value; +template <typename BasicJsonType, typename T> +struct has_from_json<BasicJsonType, T, + enable_if_t<not is_basic_json<T>::value>> +{ + using serializer = typename BasicJsonType::template json_serializer<T, void>; + + static constexpr bool value = + is_detected_exact<void, from_json_function, serializer, + const BasicJsonType&, T&>::value; }; // This trait checks if JSONSerializer<T>::from_json(json const&) exists // this overload is used for non-default-constructible user-defined-types -template<typename BasicJsonType, typename T> -struct has_non_default_from_json -{ - private: - template < - typename U, - typename = enable_if_t<std::is_same< - T, decltype(uncvref_t<U>::from_json(std::declval<BasicJsonType>()))>::value >> - static int detect(U&&); - static void detect(...); +template <typename BasicJsonType, typename T, typename = void> +struct has_non_default_from_json : std::false_type {}; - public: - static constexpr bool value = std::is_integral<decltype(detect( - std::declval<typename BasicJsonType::template json_serializer<T, void>>()))>::value; +template<typename BasicJsonType, typename T> +struct has_non_default_from_json<BasicJsonType, T, enable_if_t<not is_basic_json<T>::value>> +{ + using serializer = typename BasicJsonType::template json_serializer<T, void>; + + static constexpr bool value = + is_detected_exact<T, from_json_function, serializer, + const BasicJsonType&>::value; }; // This trait checks if BasicJsonType::json_serializer<T>::to_json exists -template<typename BasicJsonType, typename T> -struct has_to_json -{ - private: - template<typename U, typename = decltype(uncvref_t<U>::to_json( - std::declval<BasicJsonType&>(), std::declval<T>()))> - static int detect(U&&); - static void detect(...); +// Do not evaluate the trait when T is a basic_json type, to avoid template instantiation infinite recursion. +template <typename BasicJsonType, typename T, typename = void> +struct has_to_json : std::false_type {}; - public: - static constexpr bool value = std::is_integral<decltype(detect( - std::declval<typename BasicJsonType::template json_serializer<T, void>>()))>::value; +template <typename BasicJsonType, typename T> +struct has_to_json<BasicJsonType, T, enable_if_t<not is_basic_json<T>::value>> +{ + using serializer = typename BasicJsonType::template json_serializer<T, void>; + + static constexpr bool value = + is_detected_exact<void, to_json_function, serializer, BasicJsonType&, + T>::value; }; -template <typename BasicJsonType, typename CompatibleCompleteType> -struct is_compatible_complete_type +template <typename BasicJsonType, typename CompatibleType, typename = void> +struct is_compatible_type_impl: std::false_type {}; + +template <typename BasicJsonType, typename CompatibleType> +struct is_compatible_type_impl < + BasicJsonType, CompatibleType, + enable_if_t<is_complete_type<CompatibleType>::value >> { static constexpr bool value = - not std::is_base_of<std::istream, CompatibleCompleteType>::value and - not is_basic_json<CompatibleCompleteType>::value and - not is_basic_json_nested_type<BasicJsonType, CompatibleCompleteType>::value and - has_to_json<BasicJsonType, CompatibleCompleteType>::value; + has_to_json<BasicJsonType, CompatibleType>::value; }; template <typename BasicJsonType, typename CompatibleType> struct is_compatible_type - : conjunction<is_complete_type<CompatibleType>, - is_compatible_complete_type<BasicJsonType, CompatibleType>> -{ -}; + : is_compatible_type_impl<BasicJsonType, CompatibleType> {}; } } @@ -1079,16 +1155,6 @@ void from_json(const BasicJsonType& j, EnumType& e) e = static_cast<EnumType>(val); } -template<typename BasicJsonType> -void from_json(const BasicJsonType& j, typename BasicJsonType::array_t& arr) -{ - if (JSON_UNLIKELY(not j.is_array())) - { - JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); - } - arr = *j.template get_ptr<const typename BasicJsonType::array_t*>(); -} - // forward_list doesn't have an insert method template<typename BasicJsonType, typename T, typename Allocator, enable_if_t<std::is_convertible<BasicJsonType, T>::value, int> = 0> @@ -1118,24 +1184,28 @@ void from_json(const BasicJsonType& j, std::valarray<T>& l) std::copy(j.m_value.array->begin(), j.m_value.array->end(), std::begin(l)); } -template<typename BasicJsonType, typename CompatibleArrayType> -void from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<0> /*unused*/) +template<typename BasicJsonType> +void from_json_array_impl(const BasicJsonType& j, typename BasicJsonType::array_t& arr, priority_tag<3> /*unused*/) { - using std::end; + arr = *j.template get_ptr<const typename BasicJsonType::array_t*>(); +} - std::transform(j.begin(), j.end(), - std::inserter(arr, end(arr)), [](const BasicJsonType & i) +template <typename BasicJsonType, typename T, std::size_t N> +auto from_json_array_impl(const BasicJsonType& j, std::array<T, N>& arr, + priority_tag<2> /*unused*/) +-> decltype(j.template get<T>(), void()) +{ + for (std::size_t i = 0; i < N; ++i) { - // get<BasicJsonType>() returns *this, this won't call a from_json - // method when value_type is BasicJsonType - return i.template get<typename CompatibleArrayType::value_type>(); - }); + arr[i] = j.at(i).template get<T>(); + } } template<typename BasicJsonType, typename CompatibleArrayType> auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<1> /*unused*/) -> decltype( arr.reserve(std::declval<typename CompatibleArrayType::size_type>()), + j.template get<typename CompatibleArrayType::value_type>(), void()) { using std::end; @@ -1150,25 +1220,34 @@ auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, prio }); } -template<typename BasicJsonType, typename T, std::size_t N> -void from_json_array_impl(const BasicJsonType& j, std::array<T, N>& arr, priority_tag<2> /*unused*/) +template <typename BasicJsonType, typename CompatibleArrayType> +void from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, + priority_tag<0> /*unused*/) { - for (std::size_t i = 0; i < N; ++i) + using std::end; + + std::transform( + j.begin(), j.end(), std::inserter(arr, end(arr)), + [](const BasicJsonType & i) { - arr[i] = j.at(i).template get<T>(); - } + // get<BasicJsonType>() returns *this, this won't call a from_json + // method when value_type is BasicJsonType + return i.template get<typename CompatibleArrayType::value_type>(); + }); } -template < - typename BasicJsonType, typename CompatibleArrayType, - enable_if_t < - is_compatible_array_type<BasicJsonType, CompatibleArrayType>::value and - not std::is_same<typename BasicJsonType::array_t, - CompatibleArrayType>::value and - std::is_constructible < - BasicJsonType, typename CompatibleArrayType::value_type >::value, - int > = 0 > -void from_json(const BasicJsonType& j, CompatibleArrayType& arr) +template <typename BasicJsonType, typename CompatibleArrayType, + enable_if_t < + is_compatible_array_type<BasicJsonType, CompatibleArrayType>::value and + not is_compatible_object_type<BasicJsonType, CompatibleArrayType>::value and + not is_compatible_string_type<BasicJsonType, CompatibleArrayType>::value and + not is_basic_json<CompatibleArrayType>::value, + int > = 0 > + +auto from_json(const BasicJsonType& j, CompatibleArrayType& arr) +-> decltype(from_json_array_impl(j, arr, priority_tag<3> {}), +j.template get<typename CompatibleArrayType::value_type>(), +void()) { if (JSON_UNLIKELY(not j.is_array())) { @@ -1176,7 +1255,7 @@ void from_json(const BasicJsonType& j, CompatibleArrayType& arr) std::string(j.type_name()))); } - from_json_array_impl(j, arr, priority_tag<2> {}); + from_json_array_impl(j, arr, priority_tag<3> {}); } template<typename BasicJsonType, typename CompatibleObjectType, @@ -1299,35 +1378,13 @@ void from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyE struct from_json_fn { - private: template<typename BasicJsonType, typename T> - auto call(const BasicJsonType& j, T& val, priority_tag<1> /*unused*/) const + auto operator()(const BasicJsonType& j, T& val) const noexcept(noexcept(from_json(j, val))) -> decltype(from_json(j, val), void()) { return from_json(j, val); } - - template<typename BasicJsonType, typename T> - void call(const BasicJsonType& /*unused*/, T& /*unused*/, priority_tag<0> /*unused*/) const noexcept - { - static_assert(sizeof(BasicJsonType) == 0, - "could not find from_json() method in T's namespace"); -#ifdef _MSC_VER - // MSVC does not show a stacktrace for the above assert - using decayed = uncvref_t<T>; - static_assert(sizeof(typename decayed::force_msvc_stacktrace) == 0, - "forcing MSVC stacktrace to show which T we're talking about."); -#endif - } - - public: - template<typename BasicJsonType, typename T> - void operator()(const BasicJsonType& j, T& val) const - noexcept(noexcept(std::declval<from_json_fn>().call(j, val, priority_tag<1> {}))) - { - return call(j, val, priority_tag<1> {}); - } }; } @@ -1724,10 +1781,14 @@ void to_json(BasicJsonType& j, const std::vector<bool>& e) external_constructor<value_t::array>::construct(j, e); } -template<typename BasicJsonType, typename CompatibleArrayType, - enable_if_t<is_compatible_array_type<BasicJsonType, CompatibleArrayType>::value or - std::is_same<typename BasicJsonType::array_t, CompatibleArrayType>::value, - int> = 0> +template <typename BasicJsonType, typename CompatibleArrayType, + enable_if_t<is_compatible_array_type<BasicJsonType, + CompatibleArrayType>::value and + not is_compatible_object_type< + BasicJsonType, CompatibleArrayType>::value and + not is_compatible_string_type<BasicJsonType, CompatibleArrayType>::value and + not is_basic_json<CompatibleArrayType>::value, + int> = 0> void to_json(BasicJsonType& j, const CompatibleArrayType& arr) { external_constructor<value_t::array>::construct(j, arr); @@ -1747,7 +1808,7 @@ void to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr) } template<typename BasicJsonType, typename CompatibleObjectType, - enable_if_t<is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value, int> = 0> + enable_if_t<is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value and not is_basic_json<CompatibleObjectType>::value, int> = 0> void to_json(BasicJsonType& j, const CompatibleObjectType& obj) { external_constructor<value_t::object>::construct(j, obj); @@ -1759,9 +1820,12 @@ void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj) external_constructor<value_t::object>::construct(j, std::move(obj)); } -template<typename BasicJsonType, typename T, std::size_t N, - enable_if_t<not std::is_constructible<typename BasicJsonType::string_t, T (&)[N]>::value, int> = 0> -void to_json(BasicJsonType& j, T (&arr)[N]) +template < + typename BasicJsonType, typename T, std::size_t N, + enable_if_t<not std::is_constructible<typename BasicJsonType::string_t, + const T (&)[N]>::value, + int> = 0 > +void to_json(BasicJsonType& j, const T (&arr)[N]) { external_constructor<value_t::array>::construct(j, arr); } @@ -1794,35 +1858,12 @@ void to_json(BasicJsonType& j, const std::tuple<Args...>& t) struct to_json_fn { - private: template<typename BasicJsonType, typename T> - auto call(BasicJsonType& j, T&& val, priority_tag<1> /*unused*/) const noexcept(noexcept(to_json(j, std::forward<T>(val)))) + auto operator()(BasicJsonType& j, T&& val) const noexcept(noexcept(to_json(j, std::forward<T>(val)))) -> decltype(to_json(j, std::forward<T>(val)), void()) { return to_json(j, std::forward<T>(val)); } - - template<typename BasicJsonType, typename T> - void call(BasicJsonType& /*unused*/, T&& /*unused*/, priority_tag<0> /*unused*/) const noexcept - { - static_assert(sizeof(BasicJsonType) == 0, - "could not find to_json() method in T's namespace"); - -#ifdef _MSC_VER - // MSVC does not show a stacktrace for the above assert - using decayed = uncvref_t<T>; - static_assert(sizeof(typename decayed::force_msvc_stacktrace) == 0, - "forcing MSVC stacktrace to show which T we're talking about."); -#endif - } - - public: - template<typename BasicJsonType, typename T> - void operator()(BasicJsonType& j, T&& val) const - noexcept(noexcept(std::declval<to_json_fn>().call(j, std::forward<T>(val), priority_tag<1> {}))) - { - return call(j, std::forward<T>(val), priority_tag<1> {}); - } }; } @@ -1952,38 +1993,66 @@ class input_buffer_adapter : public input_adapter_protocol const char* const limit; }; -template<typename WideStringType> -class wide_string_input_adapter : public input_adapter_protocol +template<typename WideStringType, size_t T> +struct wide_string_input_helper { - public: - explicit wide_string_input_adapter(const WideStringType& w) : str(w) {} - - std::char_traits<char>::int_type get_character() noexcept override + // UTF-32 + static void fill_buffer(const WideStringType& str, size_t& current_wchar, std::array<std::char_traits<char>::int_type, 4>& utf8_bytes, size_t& utf8_bytes_index, size_t& utf8_bytes_filled) { - // check if buffer needs to be filled - if (utf8_bytes_index == utf8_bytes_filled) + utf8_bytes_index = 0; + + if (current_wchar == str.size()) { - if (sizeof(typename WideStringType::value_type) == 2) + utf8_bytes[0] = std::char_traits<char>::eof(); + utf8_bytes_filled = 1; + } + else + { + // get the current character + const int wc = static_cast<int>(str[current_wchar++]); + + // UTF-32 to UTF-8 encoding + if (wc < 0x80) { - fill_buffer_utf16(); + utf8_bytes[0] = wc; + utf8_bytes_filled = 1; + } + else if (wc <= 0x7FF) + { + utf8_bytes[0] = 0xC0 | ((wc >> 6) & 0x1F); + utf8_bytes[1] = 0x80 | (wc & 0x3F); + utf8_bytes_filled = 2; + } + else if (wc <= 0xFFFF) + { + utf8_bytes[0] = 0xE0 | ((wc >> 12) & 0x0F); + utf8_bytes[1] = 0x80 | ((wc >> 6) & 0x3F); + utf8_bytes[2] = 0x80 | (wc & 0x3F); + utf8_bytes_filled = 3; + } + else if (wc <= 0x10FFFF) + { + utf8_bytes[0] = 0xF0 | ((wc >> 18) & 0x07); + utf8_bytes[1] = 0x80 | ((wc >> 12) & 0x3F); + utf8_bytes[2] = 0x80 | ((wc >> 6) & 0x3F); + utf8_bytes[3] = 0x80 | (wc & 0x3F); + utf8_bytes_filled = 4; } else { - fill_buffer_utf32(); + // unknown character + utf8_bytes[0] = wc; + utf8_bytes_filled = 1; } - - assert(utf8_bytes_filled > 0); - assert(utf8_bytes_index == 0); } - - // use buffer - assert(utf8_bytes_filled > 0); - assert(utf8_bytes_index < utf8_bytes_filled); - return utf8_bytes[utf8_bytes_index++]; } +}; - private: - void fill_buffer_utf16() +template<typename WideStringType> +struct wide_string_input_helper<WideStringType, 2> +{ + // UTF-16 + static void fill_buffer(const WideStringType& str, size_t& current_wchar, std::array<std::char_traits<char>::int_type, 4>& utf8_bytes, size_t& utf8_bytes_index, size_t& utf8_bytes_filled) { utf8_bytes_index = 0; @@ -2038,58 +2107,38 @@ class wide_string_input_adapter : public input_adapter_protocol } } } +}; - void fill_buffer_utf32() +template<typename WideStringType> +class wide_string_input_adapter : public input_adapter_protocol +{ + public: + explicit wide_string_input_adapter(const WideStringType& w) : str(w) {} + + std::char_traits<char>::int_type get_character() noexcept override { - utf8_bytes_index = 0; - - if (current_wchar == str.size()) + // check if buffer needs to be filled + if (utf8_bytes_index == utf8_bytes_filled) { - utf8_bytes[0] = std::char_traits<char>::eof(); - utf8_bytes_filled = 1; - } - else - { - // get the current character - const int wc = static_cast<int>(str[current_wchar++]); + fill_buffer<sizeof(typename WideStringType::value_type)>(); - // UTF-32 to UTF-8 encoding - if (wc < 0x80) - { - utf8_bytes[0] = wc; - utf8_bytes_filled = 1; - } - else if (wc <= 0x7FF) - { - utf8_bytes[0] = 0xC0 | ((wc >> 6) & 0x1F); - utf8_bytes[1] = 0x80 | (wc & 0x3F); - utf8_bytes_filled = 2; - } - else if (wc <= 0xFFFF) - { - utf8_bytes[0] = 0xE0 | ((wc >> 12) & 0x0F); - utf8_bytes[1] = 0x80 | ((wc >> 6) & 0x3F); - utf8_bytes[2] = 0x80 | (wc & 0x3F); - utf8_bytes_filled = 3; - } - else if (wc <= 0x10FFFF) - { - utf8_bytes[0] = 0xF0 | ((wc >> 18 ) & 0x07); - utf8_bytes[1] = 0x80 | ((wc >> 12) & 0x3F); - utf8_bytes[2] = 0x80 | ((wc >> 6) & 0x3F); - utf8_bytes[3] = 0x80 | (wc & 0x3F); - utf8_bytes_filled = 4; - } - else - { - // unknown character - utf8_bytes[0] = wc; - utf8_bytes_filled = 1; - } + assert(utf8_bytes_filled > 0); + assert(utf8_bytes_index == 0); } + + // use buffer + assert(utf8_bytes_filled > 0); + assert(utf8_bytes_index < utf8_bytes_filled); + return utf8_bytes[utf8_bytes_index++]; } private: + template<size_t T> + void fill_buffer() + { + wide_string_input_helper<WideStringType, T>::fill_buffer(str, current_wchar, utf8_bytes, utf8_bytes_index, utf8_bytes_filled); + } + /// the wstring to process const WideStringType& str; @@ -2157,15 +2206,18 @@ class input_adapter int>::type = 0> input_adapter(IteratorType first, IteratorType last) { +#ifndef NDEBUG // assertion to check that the iterator range is indeed contiguous, // see http://stackoverflow.com/a/35008842/266378 for more discussion - assert(std::accumulate( - first, last, std::pair<bool, int>(true, 0), - [&first](std::pair<bool, int> res, decltype(*first) val) + const auto is_contiguous = std::accumulate( + first, last, std::pair<bool, int>(true, 0), + [&first](std::pair<bool, int> res, decltype(*first) val) { res.first &= (val == *(std::next(std::addressof(*first), res.second++))); return res; - }).first); + }).first; + assert(is_contiguous); +#endif // assertion to check that each element is 1 byte long static_assert( @@ -3569,73 +3621,6 @@ scan_number_done: // #include <nlohmann/detail/meta/detected.hpp> - -#include <type_traits> - -// #include <nlohmann/detail/meta/void_t.hpp> - - -namespace nlohmann -{ -namespace detail -{ -template <typename...> -using void_t = void; -} -} - - -// http://en.cppreference.com/w/cpp/experimental/is_detected -namespace nlohmann -{ -namespace detail -{ -struct nonesuch -{ - nonesuch() = delete; - ~nonesuch() = delete; - nonesuch(nonesuch const&) = delete; - void operator=(nonesuch const&) = delete; -}; - -template <class Default, - class AlwaysVoid, - template <class...> class Op, - class... Args> -struct detector -{ - using value_t = std::false_type; - using type = Default; -}; - -template <class Default, template <class...> class Op, class... Args> -struct detector<Default, void_t<Op<Args...>>, Op, Args...> -{ - using value_t = std::true_type; - using type = Op<Args...>; -}; - -template <template <class...> class Op, class... Args> -using is_detected = typename detector<nonesuch, void, Op, Args...>::value_t; - -template <template <class...> class Op, class... Args> -using detected_t = typename detector<nonesuch, void, Op, Args...>::type; - -template <class Default, template <class...> class Op, class... Args> -using detected_or = detector<Default, void, Op, Args...>; - -template <class Default, template <class...> class Op, class... Args> -using detected_or_t = typename detected_or<Default, Op, Args...>::type; - -template <class Expected, template <class...> class Op, class... Args> -using is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>; - -template <class To, template <class...> class Op, class... Args> -using is_detected_convertible = - std::is_convertible<detected_t<Op, Args...>, To>; -} -} - // #include <nlohmann/detail/meta/type_traits.hpp> @@ -10172,7 +10157,7 @@ class serializer return; } - const bool is_negative = (x <= 0) and (x != 0); // see issue #755 + const bool is_negative = not (x >= 0); // see issue #755 std::size_t i = 0; while (x != 0) @@ -11151,8 +11136,10 @@ struct adl_serializer @param[in,out] val value to write to */ template<typename BasicJsonType, typename ValueType> - static void from_json(BasicJsonType&& j, ValueType& val) noexcept( - noexcept(::nlohmann::from_json(std::forward<BasicJsonType>(j), val))) + static auto from_json(BasicJsonType&& j, ValueType& val) noexcept( + noexcept(::nlohmann::from_json(std::forward<BasicJsonType>(j), val))) -> decltype( + ::nlohmann::from_json(std::forward<BasicJsonType>(j), val), void() + ) { ::nlohmann::from_json(std::forward<BasicJsonType>(j), val); } @@ -11166,9 +11153,11 @@ struct adl_serializer @param[in,out] j JSON value to write to @param[in] val value to read from */ - template<typename BasicJsonType, typename ValueType> - static void to_json(BasicJsonType& j, ValueType&& val) noexcept( + template <typename BasicJsonType, typename ValueType> + static auto to_json(BasicJsonType& j, ValueType&& val) noexcept( noexcept(::nlohmann::to_json(j, std::forward<ValueType>(val)))) + -> decltype(::nlohmann::to_json(j, std::forward<ValueType>(val)), + void()) { ::nlohmann::to_json(j, std::forward<ValueType>(val)); } @@ -12053,7 +12042,7 @@ class basic_json object = nullptr; // silence warning, see #821 if (JSON_UNLIKELY(t == value_t::null)) { - JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.2.0")); // LCOV_EXCL_LINE + JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.3.0")); // LCOV_EXCL_LINE } break; } @@ -12349,7 +12338,7 @@ class basic_json template <typename CompatibleType, typename U = detail::uncvref_t<CompatibleType>, detail::enable_if_t< - detail::is_compatible_type<basic_json_t, U>::value, int> = 0> + not detail::is_basic_json<U>::value and detail::is_compatible_type<basic_json_t, U>::value, int> = 0> basic_json(CompatibleType && val) noexcept(noexcept( JSONSerializer<U>::to_json(std::declval<basic_json_t&>(), std::forward<CompatibleType>(val)))) @@ -13730,51 +13719,50 @@ class basic_json } /*! - @brief get a pointer value (explicit) + @brief get a value (explicit) - Explicit pointer access to the internally stored JSON value. No copies are - made. + Explicit type conversion between the JSON value and a compatible value. + The value is filled into the input parameter by calling the @ref json_serializer<ValueType> + `from_json()` method. - @warning The pointer becomes invalid if the underlying JSON object - changes. + The function is equivalent to executing + @code {.cpp} + ValueType v; + JSONSerializer<ValueType>::from_json(*this, v); + @endcode - @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref - object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, - @ref number_unsigned_t, or @ref number_float_t. + This overloads is chosen if: + - @a ValueType is not @ref basic_json, + - @ref json_serializer<ValueType> has a `from_json()` method of the form + `void from_json(const basic_json&, ValueType&)`, and - @return pointer to the internally stored JSON value if the requested - pointer type @a PointerType fits to the JSON value; `nullptr` otherwise + @tparam ValueType the input parameter type. - @complexity Constant. + @return the input parameter, allowing chaining calls. - @liveexample{The example below shows how pointers to internal values of a - JSON value can be requested. Note that no type conversions are made and a - `nullptr` is returned if the value and the requested pointer type does not - match.,get__PointerType} + @throw what @ref json_serializer<ValueType> `from_json()` method throws - @sa @ref get_ptr() for explicit pointer-member access + @liveexample{The example below shows several conversions from JSON values + to other types. There a few things to note: (1) Floating-point numbers can + be converted to integers\, (2) A JSON array can be converted to a standard + `std::vector<short>`\, (3) A JSON object can be converted to C++ + associative containers such as `std::unordered_map<std::string\, + json>`.,get_to} - @since version 1.0.0 + @since version 3.3.0 */ - template<typename PointerType, typename std::enable_if< - std::is_pointer<PointerType>::value, int>::type = 0> - PointerType get() noexcept + template<typename ValueType, + detail::enable_if_t < + not detail::is_basic_json<ValueType>::value and + detail::has_from_json<basic_json_t, ValueType>::value, + int> = 0> + ValueType & get_to(ValueType& v) const noexcept(noexcept( + JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>(), v))) { - // delegate the call to get_ptr - return get_ptr<PointerType>(); + JSONSerializer<ValueType>::from_json(*this, v); + return v; } - /*! - @brief get a pointer value (explicit) - @copydoc get() - */ - template<typename PointerType, typename std::enable_if< - std::is_pointer<PointerType>::value, int>::type = 0> - constexpr const PointerType get() const noexcept - { - // delegate the call to get_ptr - return get_ptr<PointerType>(); - } /*! @brief get a pointer value (implicit) @@ -13804,23 +13792,8 @@ class basic_json */ template<typename PointerType, typename std::enable_if< std::is_pointer<PointerType>::value, int>::type = 0> - PointerType get_ptr() noexcept + auto get_ptr() noexcept -> decltype(std::declval<basic_json_t&>().get_impl_ptr(std::declval<PointerType>())) { - // get the type of the PointerType (remove pointer and const) - using pointee_t = typename std::remove_const<typename - std::remove_pointer<typename - std::remove_const<PointerType>::type>::type>::type; - // make sure the type matches the allowed types - static_assert( - std::is_same<object_t, pointee_t>::value - or std::is_same<array_t, pointee_t>::value - or std::is_same<string_t, pointee_t>::value - or std::is_same<boolean_t, pointee_t>::value - or std::is_same<number_integer_t, pointee_t>::value - or std::is_same<number_unsigned_t, pointee_t>::value - or std::is_same<number_float_t, pointee_t>::value - , "incompatible pointer type"); - // delegate the call to get_impl_ptr<>() return get_impl_ptr(static_cast<PointerType>(nullptr)); } @@ -13832,27 +13805,59 @@ class basic_json template<typename PointerType, typename std::enable_if< std::is_pointer<PointerType>::value and std::is_const<typename std::remove_pointer<PointerType>::type>::value, int>::type = 0> - constexpr const PointerType get_ptr() const noexcept + constexpr auto get_ptr() const noexcept -> decltype(std::declval<const basic_json_t&>().get_impl_ptr(std::declval<PointerType>())) { - // get the type of the PointerType (remove pointer and const) - using pointee_t = typename std::remove_const<typename - std::remove_pointer<typename - std::remove_const<PointerType>::type>::type>::type; - // make sure the type matches the allowed types - static_assert( - std::is_same<object_t, pointee_t>::value - or std::is_same<array_t, pointee_t>::value - or std::is_same<string_t, pointee_t>::value - or std::is_same<boolean_t, pointee_t>::value - or std::is_same<number_integer_t, pointee_t>::value - or std::is_same<number_unsigned_t, pointee_t>::value - or std::is_same<number_float_t, pointee_t>::value - , "incompatible pointer type"); - // delegate the call to get_impl_ptr<>() const return get_impl_ptr(static_cast<PointerType>(nullptr)); } + /*! + @brief get a pointer value (explicit) + + Explicit pointer access to the internally stored JSON value. No copies are + made. + + @warning The pointer becomes invalid if the underlying JSON object + changes. + + @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref + object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, + @ref number_unsigned_t, or @ref number_float_t. + + @return pointer to the internally stored JSON value if the requested + pointer type @a PointerType fits to the JSON value; `nullptr` otherwise + + @complexity Constant. + + @liveexample{The example below shows how pointers to internal values of a + JSON value can be requested. Note that no type conversions are made and a + `nullptr` is returned if the value and the requested pointer type does not + match.,get__PointerType} + + @sa @ref get_ptr() for explicit pointer-member access + + @since version 1.0.0 + */ + template<typename PointerType, typename std::enable_if< + std::is_pointer<PointerType>::value, int>::type = 0> + auto get() noexcept -> decltype(std::declval<basic_json_t&>().template get_ptr<PointerType>()) + { + // delegate the call to get_ptr + return get_ptr<PointerType>(); + } + + /*! + @brief get a pointer value (explicit) + @copydoc get() + */ + template<typename PointerType, typename std::enable_if< + std::is_pointer<PointerType>::value, int>::type = 0> + constexpr auto get() const noexcept -> decltype(std::declval<const basic_json_t&>().template get_ptr<PointerType>()) + { + // delegate the call to get_ptr + return get_ptr<PointerType>(); + } + /*! @brief get a reference value (implicit) @@ -13934,12 +13939,14 @@ class basic_json not std::is_same<ValueType, detail::json_ref<basic_json>>::value and not std::is_same<ValueType, typename string_t::value_type>::value and not detail::is_basic_json<ValueType>::value + #ifndef _MSC_VER // fix for issue #167 operator<< ambiguity under VS2015 and not std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value #if defined(JSON_HAS_CPP_17) && defined(_MSC_VER) and _MSC_VER <= 1914 and not 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 , int >::type = 0 > operator ValueType() const { @@ -14203,7 +14210,7 @@ class basic_json return m_value.array->operator[](idx); } - JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); + JSON_THROW(type_error::create(305, "cannot use operator[] with a numeric argument with " + std::string(type_name()))); } /*! @@ -14233,7 +14240,7 @@ class basic_json return m_value.array->operator[](idx); } - JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); + JSON_THROW(type_error::create(305, "cannot use operator[] with a numeric argument with " + std::string(type_name()))); } /*! @@ -14279,7 +14286,7 @@ class basic_json return m_value.object->operator[](key); } - JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); + JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()))); } /*! @@ -14321,7 +14328,7 @@ class basic_json return m_value.object->find(key)->second; } - JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); + JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()))); } /*! @@ -14368,7 +14375,7 @@ class basic_json return m_value.object->operator[](key); } - JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); + JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()))); } /*! @@ -14411,7 +14418,7 @@ class basic_json return m_value.object->find(key)->second; } - JSON_THROW(type_error::create(305, "cannot use operator[] with " + std::string(type_name()))); + JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()))); } /*! @@ -16049,6 +16056,26 @@ class basic_json return {it, res.second}; } + /// Helper for insertion of an iterator + /// @note: This uses std::distance to support GCC 4.8, + /// see https://github.com/nlohmann/json/pull/1257 + template<typename... Args> + iterator insert_iterator(const_iterator pos, Args&& ... args) + { + iterator result(this); + assert(m_value.array != nullptr); + + 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)...); + result.m_it.array_iterator = m_value.array->begin() + insert_pos; + + // This could have been written as: + // result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val); + // but the return value of insert is missing in GCC 4.8, so it is written this way instead. + + return result; + } + /*! @brief inserts element @@ -16083,9 +16110,7 @@ class basic_json } // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, val); - return result; + return insert_iterator(pos, val); } JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); @@ -16136,9 +16161,7 @@ class basic_json } // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val); - return result; + return insert_iterator(pos, cnt, val); } JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); @@ -16200,12 +16223,7 @@ class basic_json } // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert( - pos.m_it.array_iterator, - first.m_it.array_iterator, - last.m_it.array_iterator); - return result; + return insert_iterator(pos, first.m_it.array_iterator, last.m_it.array_iterator); } /*! @@ -16247,9 +16265,7 @@ class basic_json } // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, ilist.begin(), ilist.end()); - return result; + return insert_iterator(pos, ilist.begin(), ilist.end()); } /*! @@ -18797,19 +18813,6 @@ class basic_json // specialization of std::swap, and std::hash namespace std { -/*! -@brief exchanges the values of two JSON objects - -@since version 1.0.0 -*/ -template<> -inline void swap<nlohmann::json>(nlohmann::json& j1, nlohmann::json& j2) noexcept( - is_nothrow_move_constructible<nlohmann::json>::value and - is_nothrow_move_assignable<nlohmann::json>::value -) -{ - j1.swap(j2); -} /// hash value for JSON objects template<> @@ -18845,6 +18848,20 @@ struct less< ::nlohmann::detail::value_t> } }; +/*! +@brief exchanges the values of two JSON objects + +@since version 1.0.0 +*/ +template<> +inline void swap<nlohmann::json>(nlohmann::json& j1, nlohmann::json& j2) noexcept( + is_nothrow_move_constructible<nlohmann::json>::value and + is_nothrow_move_assignable<nlohmann::json>::value +) +{ + j1.swap(j2); +} + } // namespace std /*! @@ -18906,7 +18923,6 @@ inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std #undef JSON_HAS_CPP_17 #undef NLOHMANN_BASIC_JSON_TPL_DECLARATION #undef NLOHMANN_BASIC_JSON_TPL -#undef NLOHMANN_JSON_HAS_HELPER #endif diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index c0f40728..04acdaab 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -96,22 +96,21 @@ foreach(file ${files}) string(REGEX REPLACE "unit-([^$]+)" "test-\\1" testcase ${file_basename}) add_executable(${testcase} $<TARGET_OBJECTS:catch_main> ${file}) - set_target_properties(${testcase} PROPERTIES - COMPILE_DEFINITIONS "$<$<CXX_COMPILER_ID:MSVC>:_SCL_SECURE_NO_WARNINGS>" - COMPILE_OPTIONS "$<$<CXX_COMPILER_ID:MSVC>:/EHsc;$<$<CONFIG:Release>:/Od>>" + target_compile_definitions(${testcase} PRIVATE + CATCH_CONFIG_FAST_COMPILE + $<$<CXX_COMPILER_ID:MSVC>:_SCL_SECURE_NO_WARNINGS> + ) + target_compile_options(${testcase} PRIVATE + $<$<CXX_COMPILER_ID:MSVC>:/EHsc;$<$<CONFIG:Release>:/Od>> + $<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Wno-deprecated;-Wno-float-equal> + $<$<CXX_COMPILER_ID:GNU>:-Wno-deprecated-declarations> + ) + target_include_directories(${testcase} PRIVATE + thirdparty/catch + thirdparty/fifo_map ) - - target_compile_definitions(${testcase} PRIVATE CATCH_CONFIG_FAST_COMPILE) - target_compile_features(${testcase} PRIVATE cxx_std_11) - target_include_directories(${testcase} PRIVATE "thirdparty/catch") - target_include_directories(${testcase} PRIVATE "thirdparty/fifo_map") - target_include_directories(${testcase} PRIVATE ${NLOHMANN_JSON_INCLUDE_BUILD_DIR}) target_link_libraries(${testcase} ${NLOHMANN_JSON_TARGET_NAME}) - if(NOT MSVC) - set_target_properties(${testcase} PROPERTIES COMPILE_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated -Wno-float-equal") - endif() - add_test(NAME "${testcase}_default" COMMAND ${testcase} ${CATCH_TEST_FILTER} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} @@ -131,5 +130,11 @@ foreach(file ${files}) ) set_tests_properties("${testcase}_valgrind" PROPERTIES LABELS "valgrind") endif() - endforeach() + +############################################################################# +# Test the generated build configs +############################################################################# +add_subdirectory(cmake_import) +add_subdirectory(cmake_import_minver) +add_subdirectory(cmake_add_subdirectory) diff --git a/test/cmake_add_subdirectory/CMakeLists.txt b/test/cmake_add_subdirectory/CMakeLists.txt new file mode 100644 index 00000000..ad04547e --- /dev/null +++ b/test/cmake_add_subdirectory/CMakeLists.txt @@ -0,0 +1,15 @@ +add_test(NAME cmake_add_subdirectory_configure + COMMAND ${CMAKE_COMMAND} + -G "${CMAKE_GENERATOR}" + -Dnlohmann_json_source=${PROJECT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/project +) +add_test(NAME cmake_add_subdirectory_build + COMMAND ${CMAKE_COMMAND} --build . +) +set_tests_properties(cmake_add_subdirectory_configure PROPERTIES + FIXTURES_SETUP cmake_add_subdirectory +) +set_tests_properties(cmake_add_subdirectory_build PROPERTIES + FIXTURES_REQUIRED cmake_add_subdirectory +) diff --git a/test/cmake_add_subdirectory/project/CMakeLists.txt b/test/cmake_add_subdirectory/project/CMakeLists.txt new file mode 100644 index 00000000..2c5be183 --- /dev/null +++ b/test/cmake_add_subdirectory/project/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 3.8) + +project(DummyImport CXX) + +set(JSON_BuildTests OFF CACHE INTERNAL "") +add_subdirectory(${nlohmann_json_source} + ${CMAKE_CURRENT_BINARY_DIR}/nlohmann_json) + +add_executable(with_namespace_target main.cpp) +target_link_libraries(with_namespace_target nlohmann_json::nlohmann_json) + +add_executable(without_namespace_target main.cpp) +target_link_libraries(without_namespace_target nlohmann_json) diff --git a/test/cmake_add_subdirectory/project/main.cpp b/test/cmake_add_subdirectory/project/main.cpp new file mode 100644 index 00000000..d2d118b8 --- /dev/null +++ b/test/cmake_add_subdirectory/project/main.cpp @@ -0,0 +1,8 @@ +#include <nlohmann/json.hpp> + +int main(int argc, char **argv) +{ + nlohmann::json j; + + return 0; +} diff --git a/test/cmake_import/CMakeLists.txt b/test/cmake_import/CMakeLists.txt new file mode 100644 index 00000000..911c342c --- /dev/null +++ b/test/cmake_import/CMakeLists.txt @@ -0,0 +1,15 @@ +add_test(NAME cmake_import_configure + COMMAND ${CMAKE_COMMAND} + -G "${CMAKE_GENERATOR}" + -Dnlohmann_json_DIR=${PROJECT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/project +) +add_test(NAME cmake_import_build + COMMAND ${CMAKE_COMMAND} --build . +) +set_tests_properties(cmake_import_configure PROPERTIES + FIXTURES_SETUP cmake_import +) +set_tests_properties(cmake_import_build PROPERTIES + FIXTURES_REQUIRED cmake_import +) diff --git a/test/cmake_import/project/CMakeLists.txt b/test/cmake_import/project/CMakeLists.txt new file mode 100644 index 00000000..d268d72c --- /dev/null +++ b/test/cmake_import/project/CMakeLists.txt @@ -0,0 +1,12 @@ +cmake_minimum_required(VERSION 3.8) + +project(DummyImport CXX) + +find_package(nlohmann_json REQUIRED) + +add_executable(with_namespace_target main.cpp) +target_link_libraries(with_namespace_target nlohmann_json::nlohmann_json) + +add_executable(without_namespace_target main.cpp) +target_link_libraries(without_namespace_target nlohmann_json) + diff --git a/test/cmake_import/project/main.cpp b/test/cmake_import/project/main.cpp new file mode 100644 index 00000000..d2d118b8 --- /dev/null +++ b/test/cmake_import/project/main.cpp @@ -0,0 +1,8 @@ +#include <nlohmann/json.hpp> + +int main(int argc, char **argv) +{ + nlohmann::json j; + + return 0; +} diff --git a/test/cmake_import_minver/CMakeLists.txt b/test/cmake_import_minver/CMakeLists.txt new file mode 100644 index 00000000..8cef2fab --- /dev/null +++ b/test/cmake_import_minver/CMakeLists.txt @@ -0,0 +1,15 @@ +add_test(NAME cmake_import_minver_configure + COMMAND ${CMAKE_COMMAND} + -G "${CMAKE_GENERATOR}" + -Dnlohmann_json_DIR=${PROJECT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/project +) +add_test(NAME cmake_import_minver_build + COMMAND ${CMAKE_COMMAND} --build . +) +set_tests_properties(cmake_import_minver_configure PROPERTIES + FIXTURES_SETUP cmake_import_minver +) +set_tests_properties(cmake_import_minver_build PROPERTIES + FIXTURES_REQUIRED cmake_import_minver +) diff --git a/test/cmake_import_minver/project/CMakeLists.txt b/test/cmake_import_minver/project/CMakeLists.txt new file mode 100644 index 00000000..eeef3296 --- /dev/null +++ b/test/cmake_import_minver/project/CMakeLists.txt @@ -0,0 +1,8 @@ +cmake_minimum_required(VERSION 3.8) + +project(DummyImportMinVer CXX) + +find_package(nlohmann_json 3.2.0 REQUIRED) + +add_executable(with_namespace_target main.cpp) +target_link_libraries(with_namespace_target nlohmann_json::nlohmann_json) diff --git a/test/cmake_import_minver/project/main.cpp b/test/cmake_import_minver/project/main.cpp new file mode 100644 index 00000000..d2d118b8 --- /dev/null +++ b/test/cmake_import_minver/project/main.cpp @@ -0,0 +1,8 @@ +#include <nlohmann/json.hpp> + +int main(int argc, char **argv) +{ + nlohmann::json j; + + return 0; +} diff --git a/test/src/fuzzer-driver_afl.cpp b/test/src/fuzzer-driver_afl.cpp index dd01b749..6c23f830 100644 --- a/test/src/fuzzer-driver_afl.cpp +++ b/test/src/fuzzer-driver_afl.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (fuzz test support) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json This file implements a driver for American Fuzzy Lop (afl-fuzz). It relies on diff --git a/test/src/fuzzer-parse_cbor.cpp b/test/src/fuzzer-parse_cbor.cpp index 20050eb7..6dd310b0 100644 --- a/test/src/fuzzer-parse_cbor.cpp +++ b/test/src/fuzzer-parse_cbor.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (fuzz test support) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json This file implements a parser test suitable for fuzz testing. Given a byte diff --git a/test/src/fuzzer-parse_json.cpp b/test/src/fuzzer-parse_json.cpp index d159a709..ed586385 100644 --- a/test/src/fuzzer-parse_json.cpp +++ b/test/src/fuzzer-parse_json.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (fuzz test support) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json This file implements a parser test suitable for fuzz testing. Given a byte diff --git a/test/src/fuzzer-parse_msgpack.cpp b/test/src/fuzzer-parse_msgpack.cpp index 0421e134..2ddf21ee 100644 --- a/test/src/fuzzer-parse_msgpack.cpp +++ b/test/src/fuzzer-parse_msgpack.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (fuzz test support) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json This file implements a parser test suitable for fuzz testing. Given a byte diff --git a/test/src/fuzzer-parse_ubjson.cpp b/test/src/fuzzer-parse_ubjson.cpp index d20f0fe2..a573e300 100644 --- a/test/src/fuzzer-parse_ubjson.cpp +++ b/test/src/fuzzer-parse_ubjson.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (fuzz test support) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json This file implements a parser test suitable for fuzz testing. Given a byte diff --git a/test/src/unit-algorithms.cpp b/test/src/unit-algorithms.cpp index c525ff11..59eb3de7 100644 --- a/test/src/unit-algorithms.cpp +++ b/test/src/unit-algorithms.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License <http://opensource.org/licenses/MIT>. diff --git a/test/src/unit-allocator.cpp b/test/src/unit-allocator.cpp index 8cf5160f..20708a4c 100644 --- a/test/src/unit-allocator.cpp +++ b/test/src/unit-allocator.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License <http://opensource.org/licenses/MIT>. diff --git a/test/src/unit-alt-string.cpp b/test/src/unit-alt-string.cpp index 356835c0..99d85678 100644 --- a/test/src/unit-alt-string.cpp +++ b/test/src/unit-alt-string.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License <http://opensource.org/licenses/MIT>. diff --git a/test/src/unit-capacity.cpp b/test/src/unit-capacity.cpp index 718d102a..cd4f9538 100644 --- a/test/src/unit-capacity.cpp +++ b/test/src/unit-capacity.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License <http://opensource.org/licenses/MIT>. diff --git a/test/src/unit-cbor.cpp b/test/src/unit-cbor.cpp index 525c7630..0d2ca939 100644 --- a/test/src/unit-cbor.cpp +++ b/test/src/unit-cbor.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License <http://opensource.org/licenses/MIT>. diff --git a/test/src/unit-class_const_iterator.cpp b/test/src/unit-class_const_iterator.cpp index 783eb048..ea039cdc 100644 --- a/test/src/unit-class_const_iterator.cpp +++ b/test/src/unit-class_const_iterator.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License <http://opensource.org/licenses/MIT>. diff --git a/test/src/unit-class_iterator.cpp b/test/src/unit-class_iterator.cpp index e8d530f7..459e0e1e 100644 --- a/test/src/unit-class_iterator.cpp +++ b/test/src/unit-class_iterator.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License <http://opensource.org/licenses/MIT>. diff --git a/test/src/unit-class_lexer.cpp b/test/src/unit-class_lexer.cpp index 65859ad5..01aee242 100644 --- a/test/src/unit-class_lexer.cpp +++ b/test/src/unit-class_lexer.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License <http://opensource.org/licenses/MIT>. diff --git a/test/src/unit-class_parser.cpp b/test/src/unit-class_parser.cpp index f9115f51..b467acd9 100644 --- a/test/src/unit-class_parser.cpp +++ b/test/src/unit-class_parser.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License <http://opensource.org/licenses/MIT>. diff --git a/test/src/unit-comparison.cpp b/test/src/unit-comparison.cpp index 3da891b6..91c47453 100644 --- a/test/src/unit-comparison.cpp +++ b/test/src/unit-comparison.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License <http://opensource.org/licenses/MIT>. diff --git a/test/src/unit-concepts.cpp b/test/src/unit-concepts.cpp index 95013c69..8ceb485b 100644 --- a/test/src/unit-concepts.cpp +++ b/test/src/unit-concepts.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License <http://opensource.org/licenses/MIT>. diff --git a/test/src/unit-constructor1.cpp b/test/src/unit-constructor1.cpp index d6040fc3..e5a1eb44 100644 --- a/test/src/unit-constructor1.cpp +++ b/test/src/unit-constructor1.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License <http://opensource.org/licenses/MIT>. diff --git a/test/src/unit-constructor2.cpp b/test/src/unit-constructor2.cpp index 14738023..4f5e11d3 100644 --- a/test/src/unit-constructor2.cpp +++ b/test/src/unit-constructor2.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License <http://opensource.org/licenses/MIT>. diff --git a/test/src/unit-convenience.cpp b/test/src/unit-convenience.cpp index 08c0b162..bbb259b6 100644 --- a/test/src/unit-convenience.cpp +++ b/test/src/unit-convenience.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License <http://opensource.org/licenses/MIT>. diff --git a/test/src/unit-conversions.cpp b/test/src/unit-conversions.cpp index fd09b230..8df21f3f 100644 --- a/test/src/unit-conversions.cpp +++ b/test/src/unit-conversions.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License <http://opensource.org/licenses/MIT>. diff --git a/test/src/unit-deserialization.cpp b/test/src/unit-deserialization.cpp index 4f9970ab..f6c75d11 100644 --- a/test/src/unit-deserialization.cpp +++ b/test/src/unit-deserialization.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License <http://opensource.org/licenses/MIT>. diff --git a/test/src/unit-element_access1.cpp b/test/src/unit-element_access1.cpp index 2954d696..96ee58b2 100644 --- a/test/src/unit-element_access1.cpp +++ b/test/src/unit-element_access1.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License <http://opensource.org/licenses/MIT>. @@ -195,7 +195,7 @@ TEST_CASE("element access 1") const json j_nonarray_const(j_nonarray); CHECK_NOTHROW(j_nonarray[0]); CHECK_THROWS_AS(j_nonarray_const[0], json::type_error&); - CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with null"); + CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with null"); } SECTION("implicit transformation to properly filled array") @@ -212,8 +212,8 @@ TEST_CASE("element access 1") const json j_nonarray_const(j_nonarray); CHECK_THROWS_AS(j_nonarray[0], json::type_error&); CHECK_THROWS_AS(j_nonarray_const[0], json::type_error&); - CHECK_THROWS_WITH(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with boolean"); - CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with boolean"); + CHECK_THROWS_WITH(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with boolean"); + CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with boolean"); } SECTION("string") @@ -222,8 +222,8 @@ TEST_CASE("element access 1") const json j_nonarray_const(j_nonarray); CHECK_THROWS_AS(j_nonarray[0], json::type_error&); CHECK_THROWS_AS(j_nonarray_const[0], json::type_error&); - CHECK_THROWS_WITH(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with string"); - CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with string"); + CHECK_THROWS_WITH(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with string"); + CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with string"); } SECTION("object") @@ -232,8 +232,8 @@ TEST_CASE("element access 1") const json j_nonarray_const(j_nonarray); CHECK_THROWS_AS(j_nonarray[0], json::type_error&); CHECK_THROWS_AS(j_nonarray_const[0], json::type_error&); - CHECK_THROWS_WITH(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with object"); - CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with object"); + CHECK_THROWS_WITH(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with object"); + CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with object"); } SECTION("number (integer)") @@ -242,8 +242,8 @@ TEST_CASE("element access 1") const json j_nonarray_const(j_nonarray); CHECK_THROWS_AS(j_nonarray[0], json::type_error&); CHECK_THROWS_AS(j_nonarray_const[0], json::type_error&); - CHECK_THROWS_WITH(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with number"); - CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with number"); + CHECK_THROWS_WITH(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with number"); + CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with number"); } SECTION("number (unsigned)") @@ -252,8 +252,8 @@ TEST_CASE("element access 1") const json j_nonarray_const(j_nonarray); CHECK_THROWS_AS(j_nonarray[0], json::type_error&); CHECK_THROWS_AS(j_nonarray_const[0], json::type_error&); - CHECK_THROWS_WITH(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with number"); - CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with number"); + CHECK_THROWS_WITH(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with number"); + CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with number"); } SECTION("number (floating-point)") @@ -262,8 +262,8 @@ TEST_CASE("element access 1") const json j_nonarray_const(j_nonarray); CHECK_THROWS_AS(j_nonarray[0], json::type_error&); CHECK_THROWS_AS(j_nonarray_const[0], json::type_error&); - CHECK_THROWS_WITH(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with number"); - CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with number"); + CHECK_THROWS_WITH(j_nonarray[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with number"); + CHECK_THROWS_WITH(j_nonarray_const[0], "[json.exception.type_error.305] cannot use operator[] with a numeric argument with number"); } } } diff --git a/test/src/unit-element_access2.cpp b/test/src/unit-element_access2.cpp index 41ec42be..c629a9ac 100644 --- a/test/src/unit-element_access2.cpp +++ b/test/src/unit-element_access2.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License <http://opensource.org/licenses/MIT>. @@ -475,9 +475,9 @@ TEST_CASE("element access 2") CHECK_NOTHROW(j_nonobject2[json::object_t::key_type("foo")]); CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error&); CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error&); - CHECK_THROWS_WITH(j_const_nonobject["foo"], "[json.exception.type_error.305] cannot use operator[] with null"); + CHECK_THROWS_WITH(j_const_nonobject["foo"], "[json.exception.type_error.305] cannot use operator[] with a string argument with null"); CHECK_THROWS_WITH(j_const_nonobject[json::object_t::key_type("foo")], - "[json.exception.type_error.305] cannot use operator[] with null"); + "[json.exception.type_error.305] cannot use operator[] with a string argument with null"); } SECTION("boolean") @@ -489,13 +489,13 @@ TEST_CASE("element access 2") CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error&); CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error&); CHECK_THROWS_WITH(j_nonobject["foo"], - "[json.exception.type_error.305] cannot use operator[] with boolean"); + "[json.exception.type_error.305] cannot use operator[] with a string argument with boolean"); CHECK_THROWS_WITH(j_nonobject[json::object_t::key_type("foo")], - "[json.exception.type_error.305] cannot use operator[] with boolean"); + "[json.exception.type_error.305] cannot use operator[] with a string argument with boolean"); CHECK_THROWS_WITH(j_const_nonobject["foo"], - "[json.exception.type_error.305] cannot use operator[] with boolean"); + "[json.exception.type_error.305] cannot use operator[] with a string argument with boolean"); CHECK_THROWS_WITH(j_const_nonobject[json::object_t::key_type("foo")], - "[json.exception.type_error.305] cannot use operator[] with boolean"); + "[json.exception.type_error.305] cannot use operator[] with a string argument with boolean"); } SECTION("string") @@ -507,13 +507,13 @@ TEST_CASE("element access 2") CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error&); CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error&); CHECK_THROWS_WITH(j_nonobject["foo"], - "[json.exception.type_error.305] cannot use operator[] with string"); + "[json.exception.type_error.305] cannot use operator[] with a string argument with string"); CHECK_THROWS_WITH(j_nonobject[json::object_t::key_type("foo")], - "[json.exception.type_error.305] cannot use operator[] with string"); + "[json.exception.type_error.305] cannot use operator[] with a string argument with string"); CHECK_THROWS_WITH(j_const_nonobject["foo"], - "[json.exception.type_error.305] cannot use operator[] with string"); + "[json.exception.type_error.305] cannot use operator[] with a string argument with string"); CHECK_THROWS_WITH(j_const_nonobject[json::object_t::key_type("foo")], - "[json.exception.type_error.305] cannot use operator[] with string"); + "[json.exception.type_error.305] cannot use operator[] with a string argument with string"); } SECTION("array") @@ -525,12 +525,12 @@ TEST_CASE("element access 2") CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error&); CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error&); CHECK_THROWS_WITH(j_nonobject["foo"], - "[json.exception.type_error.305] cannot use operator[] with array"); - CHECK_THROWS_WITH(j_nonobject[json::object_t::key_type("foo")], "[json.exception.type_error.305] cannot use operator[] with array"); + "[json.exception.type_error.305] cannot use operator[] with a string argument with array"); + CHECK_THROWS_WITH(j_nonobject[json::object_t::key_type("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with array"); CHECK_THROWS_WITH(j_const_nonobject["foo"], - "[json.exception.type_error.305] cannot use operator[] with array"); + "[json.exception.type_error.305] cannot use operator[] with a string argument with array"); CHECK_THROWS_WITH(j_const_nonobject[json::object_t::key_type("foo")], - "[json.exception.type_error.305] cannot use operator[] with array"); + "[json.exception.type_error.305] cannot use operator[] with a string argument with array"); } SECTION("number (integer)") @@ -542,13 +542,13 @@ TEST_CASE("element access 2") CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error&); CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error&); CHECK_THROWS_WITH(j_nonobject["foo"], - "[json.exception.type_error.305] cannot use operator[] with number"); + "[json.exception.type_error.305] cannot use operator[] with a string argument with number"); CHECK_THROWS_WITH(j_nonobject[json::object_t::key_type("foo")], - "[json.exception.type_error.305] cannot use operator[] with number"); + "[json.exception.type_error.305] cannot use operator[] with a string argument with number"); CHECK_THROWS_WITH(j_const_nonobject["foo"], - "[json.exception.type_error.305] cannot use operator[] with number"); + "[json.exception.type_error.305] cannot use operator[] with a string argument with number"); CHECK_THROWS_WITH(j_const_nonobject[json::object_t::key_type("foo")], - "[json.exception.type_error.305] cannot use operator[] with number"); + "[json.exception.type_error.305] cannot use operator[] with a string argument with number"); } SECTION("number (unsigned)") @@ -560,13 +560,13 @@ TEST_CASE("element access 2") CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error&); CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error&); CHECK_THROWS_WITH(j_nonobject["foo"], - "[json.exception.type_error.305] cannot use operator[] with number"); + "[json.exception.type_error.305] cannot use operator[] with a string argument with number"); CHECK_THROWS_WITH(j_nonobject[json::object_t::key_type("foo")], - "[json.exception.type_error.305] cannot use operator[] with number"); + "[json.exception.type_error.305] cannot use operator[] with a string argument with number"); CHECK_THROWS_WITH(j_const_nonobject["foo"], - "[json.exception.type_error.305] cannot use operator[] with number"); + "[json.exception.type_error.305] cannot use operator[] with a string argument with number"); CHECK_THROWS_WITH(j_const_nonobject[json::object_t::key_type("foo")], - "[json.exception.type_error.305] cannot use operator[] with number"); + "[json.exception.type_error.305] cannot use operator[] with a string argument with number"); } SECTION("number (floating-point)") @@ -578,13 +578,13 @@ TEST_CASE("element access 2") CHECK_THROWS_AS(j_const_nonobject["foo"], json::type_error&); CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], json::type_error&); CHECK_THROWS_WITH(j_nonobject["foo"], - "[json.exception.type_error.305] cannot use operator[] with number"); + "[json.exception.type_error.305] cannot use operator[] with a string argument with number"); CHECK_THROWS_WITH(j_nonobject[json::object_t::key_type("foo")], - "[json.exception.type_error.305] cannot use operator[] with number"); + "[json.exception.type_error.305] cannot use operator[] with a string argument with number"); CHECK_THROWS_WITH(j_const_nonobject["foo"], - "[json.exception.type_error.305] cannot use operator[] with number"); + "[json.exception.type_error.305] cannot use operator[] with a string argument with number"); CHECK_THROWS_WITH(j_const_nonobject[json::object_t::key_type("foo")], - "[json.exception.type_error.305] cannot use operator[] with number"); + "[json.exception.type_error.305] cannot use operator[] with a string argument with number"); } } } diff --git a/test/src/unit-inspection.cpp b/test/src/unit-inspection.cpp index 8e42c6ec..007b304d 100644 --- a/test/src/unit-inspection.cpp +++ b/test/src/unit-inspection.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License <http://opensource.org/licenses/MIT>. diff --git a/test/src/unit-items.cpp b/test/src/unit-items.cpp index 69637ee8..6c716eeb 100644 --- a/test/src/unit-items.cpp +++ b/test/src/unit-items.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License <http://opensource.org/licenses/MIT>. diff --git a/test/src/unit-iterators1.cpp b/test/src/unit-iterators1.cpp index 8c3417d5..c911ce92 100644 --- a/test/src/unit-iterators1.cpp +++ b/test/src/unit-iterators1.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License <http://opensource.org/licenses/MIT>. diff --git a/test/src/unit-iterators2.cpp b/test/src/unit-iterators2.cpp index 3d309b3c..2369cc47 100644 --- a/test/src/unit-iterators2.cpp +++ b/test/src/unit-iterators2.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License <http://opensource.org/licenses/MIT>. diff --git a/test/src/unit-json_patch.cpp b/test/src/unit-json_patch.cpp index c7c62fe5..55f2eb7d 100644 --- a/test/src/unit-json_patch.cpp +++ b/test/src/unit-json_patch.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License <http://opensource.org/licenses/MIT>. @@ -63,7 +63,7 @@ TEST_CASE("JSON patch") // is not an error, because "a" exists, and "b" will be added to // its value. CHECK_NOTHROW(doc1.patch(patch)); - CHECK(doc1.patch(patch) == R"( + auto doc1_ans = R"( { "a": { "foo": 1, @@ -72,7 +72,8 @@ TEST_CASE("JSON patch") } } } - )"_json); + )"_json; + CHECK(doc1.patch(patch) == doc1_ans); // It is an error in this document: json doc2 = R"({ "q": { "bar": 2 } })"_json; diff --git a/test/src/unit-json_pointer.cpp b/test/src/unit-json_pointer.cpp index 9f39493c..d02bd939 100644 --- a/test/src/unit-json_pointer.cpp +++ b/test/src/unit-json_pointer.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License <http://opensource.org/licenses/MIT>. diff --git a/test/src/unit-merge_patch.cpp b/test/src/unit-merge_patch.cpp index 15997e19..417e1dd4 100644 --- a/test/src/unit-merge_patch.cpp +++ b/test/src/unit-merge_patch.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License <http://opensource.org/licenses/MIT>. diff --git a/test/src/unit-meta.cpp b/test/src/unit-meta.cpp index 1fd21dbf..36d31909 100644 --- a/test/src/unit-meta.cpp +++ b/test/src/unit-meta.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License <http://opensource.org/licenses/MIT>. @@ -43,9 +43,9 @@ TEST_CASE("version information") CHECK(j["url"] == "https://github.com/nlohmann/json"); CHECK(j["version"] == json( { - {"string", "3.2.0"}, + {"string", "3.3.0"}, {"major", 3}, - {"minor", 2}, + {"minor", 3}, {"patch", 0} })); diff --git a/test/src/unit-modifiers.cpp b/test/src/unit-modifiers.cpp index a73e7cfb..5548db12 100644 --- a/test/src/unit-modifiers.cpp +++ b/test/src/unit-modifiers.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License <http://opensource.org/licenses/MIT>. diff --git a/test/src/unit-msgpack.cpp b/test/src/unit-msgpack.cpp index 60892345..0848ef08 100644 --- a/test/src/unit-msgpack.cpp +++ b/test/src/unit-msgpack.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License <http://opensource.org/licenses/MIT>. diff --git a/test/src/unit-noexcept.cpp b/test/src/unit-noexcept.cpp index 72e89267..b7df80c8 100644 --- a/test/src/unit-noexcept.cpp +++ b/test/src/unit-noexcept.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License <http://opensource.org/licenses/MIT>. diff --git a/test/src/unit-pointer_access.cpp b/test/src/unit-pointer_access.cpp index f34b0a7c..5dff33a6 100644 --- a/test/src/unit-pointer_access.cpp +++ b/test/src/unit-pointer_access.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License <http://opensource.org/licenses/MIT>. diff --git a/test/src/unit-readme.cpp b/test/src/unit-readme.cpp index 5e3255ce..d9afa1d7 100644 --- a/test/src/unit-readme.cpp +++ b/test/src/unit-readme.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License <http://opensource.org/licenses/MIT>. diff --git a/test/src/unit-reference_access.cpp b/test/src/unit-reference_access.cpp index 5bd20776..3288a14e 100644 --- a/test/src/unit-reference_access.cpp +++ b/test/src/unit-reference_access.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License <http://opensource.org/licenses/MIT>. diff --git a/test/src/unit-regression.cpp b/test/src/unit-regression.cpp index 69c0cf29..6b9fd957 100644 --- a/test/src/unit-regression.cpp +++ b/test/src/unit-regression.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License <http://opensource.org/licenses/MIT>. @@ -1427,20 +1427,26 @@ TEST_CASE("regression tests") } })"_json; - CHECK_THROWS_AS(model.patch(R"([{"op": "move", - "from": "/one/two/three", - "path": "/a/b/c"}])"_json), json::out_of_range&); - CHECK_THROWS_WITH(model.patch(R"([{"op": "move", - "from": "/one/two/three", - "path": "/a/b/c"}])"_json), + auto p1 = R"([{"op": "move", + "from": "/one/two/three", + "path": "/a/b/c"}])"_json; + CHECK_THROWS_AS(model.patch(p1), json::out_of_range&); + + auto p2 = R"([{"op": "move", + "from": "/one/two/three", + "path": "/a/b/c"}])"_json; + CHECK_THROWS_WITH(model.patch(p2), "[json.exception.out_of_range.403] key 'a' not found"); - CHECK_THROWS_AS(model.patch(R"([{"op": "copy", + auto p3 = R"([{"op": "copy", + "from": "/one/two/three", + "path": "/a/b/c"}])"_json; + CHECK_THROWS_AS(model.patch(p3), json::out_of_range&); + + auto p4 = R"([{"op": "copy", "from": "/one/two/three", - "path": "/a/b/c"}])"_json), json::out_of_range&); - CHECK_THROWS_WITH(model.patch(R"([{"op": "copy", - "from": "/one/two/three", - "path": "/a/b/c"}])"_json), + "path": "/a/b/c"}])"_json; + CHECK_THROWS_WITH(model.patch(p4), "[json.exception.out_of_range.403] key 'a' not found"); } diff --git a/test/src/unit-serialization.cpp b/test/src/unit-serialization.cpp index f2861c42..0eed7246 100644 --- a/test/src/unit-serialization.cpp +++ b/test/src/unit-serialization.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License <http://opensource.org/licenses/MIT>. diff --git a/test/src/unit-testsuites.cpp b/test/src/unit-testsuites.cpp index 237eb34e..caa6ee3e 100644 --- a/test/src/unit-testsuites.cpp +++ b/test/src/unit-testsuites.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License <http://opensource.org/licenses/MIT>. @@ -405,7 +405,7 @@ TEST_CASE("RFC 7159 examples") SECTION("13 Examples") { { - CHECK_NOTHROW(json(R"( + auto json_contents = R"( { "Image": { "Width": 800, @@ -420,11 +420,13 @@ TEST_CASE("RFC 7159 examples") "IDs": [116, 943, 234, 38793] } } - )")); + )"; + + CHECK_NOTHROW(json(json_contents)); } { - CHECK_NOTHROW(json(R"( + auto json_contents = R"( [ { "precision": "zip", @@ -446,7 +448,8 @@ TEST_CASE("RFC 7159 examples") "Zip": "94085", "Country": "US" } - ])")); + ])"; + CHECK_NOTHROW(json(json_contents)); } CHECK(json::parse("\"Hello world!\"") == json("Hello world!")); @@ -1343,13 +1346,11 @@ TEST_CASE("Big List of Naughty Strings") SECTION("roundtripping") { std::ifstream f("test/data/big-list-of-naughty-strings/blns.json"); + std::string line; - while (not f.eof()) + // read lines one by one, bail out on error or eof + while (getline(f, line)) { - // read line - std::string line; - getline(f, line); - // trim whitespace line = trim(line); diff --git a/test/src/unit-to_chars.cpp b/test/src/unit-to_chars.cpp index d4431765..f6016a6c 100644 --- a/test/src/unit-to_chars.cpp +++ b/test/src/unit-to_chars.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License <http://opensource.org/licenses/MIT>. diff --git a/test/src/unit-ubjson.cpp b/test/src/unit-ubjson.cpp index abae230b..3b060c97 100644 --- a/test/src/unit-ubjson.cpp +++ b/test/src/unit-ubjson.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License <http://opensource.org/licenses/MIT>. diff --git a/test/src/unit-udt.cpp b/test/src/unit-udt.cpp index f59999ee..fbcf027d 100644 --- a/test/src/unit-udt.cpp +++ b/test/src/unit-udt.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License <http://opensource.org/licenses/MIT>. @@ -298,6 +298,19 @@ TEST_CASE("basic usage", "[udt]") CHECK(book == parsed_book); } + SECTION("via explicit calls to get_to") + { + udt::person person; + udt::name name; + + json person_json = big_json["contacts"][0]["person"]; + CHECK(person_json.get_to(person) == sfinae_addict); + + // correct reference gets returned + person_json["name"].get_to(name).m_val = "new name"; + CHECK(name.m_val == "new name"); + } + SECTION("implicit conversions") { const udt::contact_book parsed_book = big_json; @@ -811,3 +824,9 @@ TEST_CASE("Issue #924") CHECK_NOTHROW(j.get<Evil>()); CHECK_NOTHROW(j.get<std::vector<Evil>>()); } + +TEST_CASE("Issue #1237") +{ + struct non_convertible_type {}; + static_assert(not std::is_convertible<json, non_convertible_type>::value, ""); +} diff --git a/test/src/unit-unicode.cpp b/test/src/unit-unicode.cpp index 083dec1f..ae580e3e 100644 --- a/test/src/unit-unicode.cpp +++ b/test/src/unit-unicode.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License <http://opensource.org/licenses/MIT>. diff --git a/test/src/unit-wstring.cpp b/test/src/unit-wstring.cpp index 3e83c932..9f59b9d0 100644 --- a/test/src/unit-wstring.cpp +++ b/test/src/unit-wstring.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License <http://opensource.org/licenses/MIT>. diff --git a/test/src/unit.cpp b/test/src/unit.cpp index 4f26dbdd..1852b993 100644 --- a/test/src/unit.cpp +++ b/test/src/unit.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.2.0 +| | |__ | | | | | | version 3.3.0 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License <http://opensource.org/licenses/MIT>.