diff --git a/.gitignore b/.gitignore index 8157f1a9..35dc9b42 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ fuzz-testing build build_coverage +clang_analyze_build doc/xml doc/html diff --git a/CMakeLists.txt b/CMakeLists.txt index 8d8f40b3..c0acc750 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.0.0) ## PROJECT ## name and version ## -project(nlohmann_json VERSION 3.1.1 LANGUAGES CXX) +project(nlohmann_json VERSION 3.1.2 LANGUAGES CXX) ## ## INCLUDE diff --git a/ChangeLog.md b/ChangeLog.md index e6d507ad..ea48332e 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,7 +1,46 @@ # Change Log All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). -## [v3.1.1](https://github.com/nlohmann/json/releases/tag/v3.1.1) (2018-02-12) +## [v3.1.2](https://github.com/nlohmann/json/releases/tag/v3.1.2) (2018-03-14) +[Full Changelog](https://github.com/nlohmann/json/compare/v3.1.1...v3.1.2) + +- STL containers are always serialized to a nested array like \[\[1,2,3\]\] [\#1013](https://github.com/nlohmann/json/issues/1013) +- The library doesn't want to insert an unordered\_map [\#1010](https://github.com/nlohmann/json/issues/1010) +- Convert Json to uint8\_t [\#1008](https://github.com/nlohmann/json/issues/1008) +- How to compare two JSON objects? [\#1007](https://github.com/nlohmann/json/issues/1007) +- Syntax checking [\#1003](https://github.com/nlohmann/json/issues/1003) +- more than one operator '=' matches these operands [\#1002](https://github.com/nlohmann/json/issues/1002) +- How to check if key existed [\#1000](https://github.com/nlohmann/json/issues/1000) +- nlohmann::json::parse exhaust memory in go binding [\#999](https://github.com/nlohmann/json/issues/999) +- Range-based iteration over a non-array object [\#998](https://github.com/nlohmann/json/issues/998) +- get\ for types that are not default constructible [\#996](https://github.com/nlohmann/json/issues/996) +- Prevent Null values to appear in .dump\(\) [\#995](https://github.com/nlohmann/json/issues/995) +- number parsing [\#993](https://github.com/nlohmann/json/issues/993) +- How to create a json variable? [\#990](https://github.com/nlohmann/json/issues/990) +- C2664 \(C++/CLR\) cannot convert 'nullptr' to 'nullptr &&' [\#987](https://github.com/nlohmann/json/issues/987) +- Uniform initialization from another json object differs between gcc and clang. [\#985](https://github.com/nlohmann/json/issues/985) +- Problem with adding the lib as a submodule [\#983](https://github.com/nlohmann/json/issues/983) +- UTF-8/Unicode error [\#982](https://github.com/nlohmann/json/issues/982) +- "forcing MSVC stacktrace to show which T we're talking about." error [\#980](https://github.com/nlohmann/json/issues/980) +- reverse order of serialization [\#979](https://github.com/nlohmann/json/issues/979) +- Assigning between different json types [\#977](https://github.com/nlohmann/json/issues/977) +- Support serialisation of `unique\_ptr\<\>` and `shared\_ptr\<\>` [\#975](https://github.com/nlohmann/json/issues/975) +- Unexpected end of input \(not same as one before\) [\#974](https://github.com/nlohmann/json/issues/974) +- Segfault on direct initializing json object [\#973](https://github.com/nlohmann/json/issues/973) +- Segmentation fault on G++ when trying to assign json string literal to custom json type. [\#972](https://github.com/nlohmann/json/issues/972) +- os\_defines.h:44:19: error: missing binary operator before token "\(" [\#970](https://github.com/nlohmann/json/issues/970) +- Passing an iteration object by reference to a function [\#967](https://github.com/nlohmann/json/issues/967) +- Json and fmt::lib's format\_arg\(\) [\#964](https://github.com/nlohmann/json/issues/964) +- Feature: to\_string\(const json& j\); [\#916](https://github.com/nlohmann/json/issues/916) + +- Allowing for user-defined string type in lexer/parser [\#1009](https://github.com/nlohmann/json/pull/1009) ([nlohmann](https://github.com/nlohmann)) +- dump to alternative string type, as defined in basic\_json template [\#1006](https://github.com/nlohmann/json/pull/1006) ([agrianius](https://github.com/agrianius)) +- Fix memory leak during parser callback [\#1001](https://github.com/nlohmann/json/pull/1001) ([nlohmann](https://github.com/nlohmann)) +- fixed misprinted condition detected by PVS Studio. [\#992](https://github.com/nlohmann/json/pull/992) ([bogemic](https://github.com/bogemic)) +- Fix/basic json conversion [\#986](https://github.com/nlohmann/json/pull/986) ([theodelrieu](https://github.com/theodelrieu)) +- Make integration section concise [\#981](https://github.com/nlohmann/json/pull/981) ([wla80](https://github.com/wla80)) + +## [v3.1.1](https://github.com/nlohmann/json/releases/tag/v3.1.1) (2018-02-13) [Full Changelog](https://github.com/nlohmann/json/compare/v3.1.0...v3.1.1) - Updation of child object isn't reflected in parent Object [\#968](https://github.com/nlohmann/json/issues/968) diff --git a/Makefile b/Makefile index 63c9cd78..a873292b 100644 --- a/Makefile +++ b/Makefile @@ -258,6 +258,12 @@ fuzzing-stop: cppcheck: cppcheck --enable=warning --inconclusive --force --std=c++11 $(AMALGAMATED_FILE) --error-exitcode=1 +# compile and check with Clang Static Analyzer +clang_analyze: + rm -fr clang_analyze_build + mkdir clang_analyze_build + cd clang_analyze_build ; CCC_CXX=/Users/niels/Documents/projects/llvm-clang/local/bin/clang++ /Users/niels/Documents/projects/llvm-clang/local/bin/scan-build cmake .. + /Users/niels/Documents/projects/llvm-clang/local/bin/scan-build -enable-checker alpha.core.DynamicTypeChecker,alpha.core.PointerArithm,alpha.core.PointerSub,alpha.cplusplus.DeleteWithNonVirtualDtor,alpha.cplusplus.IteratorRange,alpha.cplusplus.MisusedMovedObject,alpha.security.ArrayBoundV2,alpha.core.Conversion --use-c++=/Users/niels/Documents/projects/llvm-clang/local/bin/clang++ --view -analyze-headers -o clang_analyze_build/report.html make -j10 -C clang_analyze_build ########################################################################## # maintainer targets diff --git a/README.md b/README.md index 4aa4d828..3ed3c183 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![Coverage Status](https://img.shields.io/coveralls/nlohmann/json.svg)](https://coveralls.io/r/nlohmann/json) [![Coverity Scan Build Status](https://scan.coverity.com/projects/5550/badge.svg)](https://scan.coverity.com/projects/nlohmann-json) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/f3732b3327e34358a0e9d1fe9f661f08)](https://www.codacy.com/app/nlohmann/json?utm_source=github.com&utm_medium=referral&utm_content=nlohmann/json&utm_campaign=Badge_Grade) -[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/DfWUb7e2q2USw0Q6) +[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/TarF5pPn9NtHQjhf) [![Documentation](https://img.shields.io/badge/docs-doxygen-blue.svg)](http://nlohmann.github.io/json) [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/nlohmann/json/master/LICENSE.MIT) [![GitHub Releases](https://img.shields.io/github/release/nlohmann/json.svg)](https://github.com/nlohmann/json/releases) @@ -42,7 +42,7 @@ There are myriads of [JSON](http://json.org) libraries out there, and each may e - **Trivial integration**. Our whole code consists of a single header file [`json.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json.hpp). That's it. No library, no subproject, no dependencies, no complex build system. The class is written in vanilla C++11. All in all, everything should require no adjustment of your compiler flags or project settings. -- **Serious testing**. Our class is heavily [unit-tested](https://github.com/nlohmann/json/blob/master/test/src/unit.cpp) and covers [100%](https://coveralls.io/r/nlohmann/json) of the code, including all exceptional behavior. Furthermore, we checked with [Valgrind](http://valgrind.org) that there are no memory leaks. To maintain high quality, the project is following the [Core Infrastructure Initiative (CII) best practices](https://bestpractices.coreinfrastructure.org/projects/289). +- **Serious testing**. Our class is heavily [unit-tested](https://github.com/nlohmann/json/tree/develop/test/src) and covers [100%](https://coveralls.io/r/nlohmann/json) of the code, including all exceptional behavior. Furthermore, we checked with [Valgrind](http://valgrind.org) and the [Clang Sanitizers](https://clang.llvm.org/docs/index.html) that there are no memory leaks. [Google OSS-Fuzz](https://github.com/google/oss-fuzz/tree/master/projects/json) additionally runs fuzz tests agains all parsers 24/7, effectively executing billions of tests so far. To maintain high quality, the project is following the [Core Infrastructure Initiative (CII) best practices](https://bestpractices.coreinfrastructure.org/projects/289). Other aspects were not so important to us: @@ -55,7 +55,7 @@ See the [contribution guidelines](https://github.com/nlohmann/json/blob/master/. ## Integration -The single required source, file `json.hpp` is in the `single_include/nlohmann` directory or [released here](https://github.com/nlohmann/json/releases). All you need to do is add +[`json.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json.hpp) is the single required file in `single_include/nlohmann` or [released here](https://github.com/nlohmann/json/releases). You need to add ```cpp #include @@ -64,9 +64,9 @@ The single required source, file `json.hpp` is in the `single_include/nlohmann` using json = nlohmann::json; ``` -to the files you want to use JSON objects. That's it. Do not forget to set the necessary switches to enable C++11 (e.g., `-std=c++11` for GCC and Clang). +to the files you want to process JSON and set the necessary switches to enable C++11 (e.g., `-std=c++11` for GCC and Clang). -You can further use file [`include/nlohmann/json_fwd.hpp`](https://github.com/nlohmann/json/blob/develop/include/nlohmann/json_fwd.hpp) for forward-declarations. The installation of json_fwd.hpp (as part of cmake's install step), can be achieved by setting `-DJSON_MultipleHeaders=ON`: +You can further use file [`include/nlohmann/json_fwd.hpp`](https://github.com/nlohmann/json/blob/develop/include/nlohmann/json_fwd.hpp) for forward-declarations. The installation of json_fwd.hpp (as part of cmake's install step), can be achieved by setting `-DJSON_MultipleHeaders=ON`. ### Package Managers @@ -82,7 +82,7 @@ If you are using [Buckaroo](https://buckaroo.pm), you can install this library's If you are using [vcpkg](https://github.com/Microsoft/vcpkg/) on your project for external dependencies, then you can use the [nlohmann-json package](https://github.com/Microsoft/vcpkg/tree/master/ports/nlohmann-json). Please see the vcpkg project for any issues regarding the packaging. -If you are using [cget](http://cget.readthedocs.io/en/latest/), you can install the latest development version with `cget install nlohmann/json`. A specific version can be installed with `cget install nlohmann/json@v3.1.0`. Also, the multiple header version can be installed by adding the `-DJSON_MultipleHeaders=ON` flag (i.e., `cget install nlohmann/json -DJSON_MultipleHeaders=ON`). +If you are using [cget](http://cget.readthedocs.io/en/latest/), you can install the latest development version with `cget install nlohmann/json`. A specific version can be installed with `cget install nlohmann/json@v3.1.0`. Also, the multiple header version can be installed by adding the `-DJSON_MultipleHeaders=ON` flag (i.e., `cget install nlohmann/json -DJSON_MultipleHeaders=ON`). ## Examples @@ -111,7 +111,7 @@ Assume you want to create the JSON object } ``` -With the JSON class, you could write: +With this library, you could write: ```cpp // create an empty structure (null) @@ -155,7 +155,7 @@ json j2 = { }; ``` -Note that in all these cases, you never need to "tell" the compiler which JSON value you want to use. If you want to be explicit or express some edge cases, the functions `json::array` and `json::object` will help: +Note that in all these cases, you never need to "tell" the compiler which JSON value type you want to use. If you want to be explicit or express some edge cases, the functions [`json::array`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_aa80485befaffcadaa39965494e0b4d2e.html#aa80485befaffcadaa39965494e0b4d2e) and [`json::object`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_aa13f7c0615867542ce80337cbcf13ada.html#aa13f7c0615867542ce80337cbcf13ada) will help: ```cpp // a way to express the empty array [] @@ -174,7 +174,7 @@ json array_not_object = json::array({ {"currency", "USD"}, {"value", 42.99} }); #### To/from strings -You can create an object (deserialization) by appending `_json` to a string literal: +You can create a JSON value (deserialization) by appending `_json` to a string literal: ```cpp // create object from string literal @@ -191,14 +191,14 @@ auto j2 = R"( Note that without appending the `_json` suffix, the passed string literal is not parsed, but just used as JSON string value. That is, `json j = "{ \"happy\": true, \"pi\": 3.141 }"` would just store the string `"{ "happy": true, "pi": 3.141 }"` rather than parsing the actual object. -The above example can also be expressed explicitly using `json::parse()`: +The above example can also be expressed explicitly using [`json::parse()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_aa9676414f2e36383c4b181fe856aa3c0.html#aa9676414f2e36383c4b181fe856aa3c0): ```cpp // parse explicitly auto j3 = json::parse("{ \"happy\": true, \"pi\": 3.141 }"); ``` -You can also get a string representation (serialize): +You can also get a string representation of a JSON value (serialize): ```cpp // explicit conversion to string @@ -233,7 +233,7 @@ std::cout << cpp_string << " == " << cpp_string2 << " == " << j_string.get()` returns the originally stored string value. +[`.dump()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a5adea76fedba9898d404fef8598aa663.html#a5adea76fedba9898d404fef8598aa663) always returns the serialized value, and [`.get()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a16f9445f7629f634221a42b967cdcd43.html#a16f9445f7629f634221a42b967cdcd43) returns the originally stored string value. #### To/from streams (e.g. files, string streams) @@ -269,7 +269,7 @@ Please note that setting the exception bit for `failbit` is inappropriate for th #### Read from iterator range -You can also read JSON from an iterator range; that is, from any container accessible by iterators whose content is stored as contiguous byte sequence, for instance a `std::vector`: +You can also parse JSON from an iterator range; that is, from any container accessible by iterators whose content is stored as contiguous byte sequence, for instance a `std::vector`: ```cpp std::vector v = {'t', 'r', 'u', 'e'}; @@ -360,7 +360,7 @@ o.erase("foo"); ### Conversion from STL containers -Any sequence container (`std::array`, `std::vector`, `std::deque`, `std::forward_list`, `std::list`) whose values can be used to construct JSON types (e.g., integers, floating point numbers, Booleans, string types, or again STL containers described in this section) can be used to create a JSON array. The same holds for similar associative containers (`std::set`, `std::multiset`, `std::unordered_set`, `std::unordered_multiset`), but in these cases the order of the elements of the array depends on how the elements are ordered in the respective STL container. +Any sequence container (`std::array`, `std::vector`, `std::deque`, `std::forward_list`, `std::list`) whose values can be used to construct JSON values (e.g., integers, floating point numbers, Booleans, string types, or again STL containers described in this section) can be used to create a JSON array. The same holds for similar associative containers (`std::set`, `std::multiset`, `std::unordered_set`, `std::unordered_multiset`), but in these cases the order of the elements of the array depends on how the elements are ordered in the respective STL container. ```cpp std::vector c_vector {1, 2, 3, 4}; @@ -400,7 +400,7 @@ json j_umset(c_umset); // both entries for "one" are used // maybe ["one", "two", "one", "four"] ``` -Likewise, any associative key-value containers (`std::map`, `std::multimap`, `std::unordered_map`, `std::unordered_multimap`) whose keys can construct an `std::string` and whose values can be used to construct JSON types (see examples above) can be used to create a JSON object. Note that in case of multimaps only one key is used in the JSON object and the value depends on the internal order of the STL container. +Likewise, any associative key-value containers (`std::map`, `std::multimap`, `std::unordered_map`, `std::unordered_multimap`) whose keys can construct an `std::string` and whose values can be used to construct JSON values (see examples above) can be used to create a JSON object. Note that in case of multimaps only one key is used in the JSON object and the value depends on the internal order of the STL container. ```cpp std::map c_map { {"one", 1}, {"two", 2}, {"three", 3} }; @@ -525,7 +525,7 @@ int vi = jn.get(); ### Arbitrary types conversions -Every type can be serialized in JSON, not just STL-containers and scalar types. Usually, you would do something along those lines: +Every type can be serialized in JSON, not just STL containers and scalar types. Usually, you would do something along those lines: ```cpp namespace ns { @@ -629,7 +629,7 @@ struct adl_serializer { }; ``` -This serializer works fine when you have control over the type's namespace. However, what about `boost::optional`, or `std::filesystem::path` (C++17)? Hijacking the `boost` namespace is pretty bad, and it's illegal to add something other than template specializations to `std`... +This serializer works fine when you have control over the type's namespace. However, what about `boost::optional` or `std::filesystem::path` (C++17)? Hijacking the `boost` namespace is pretty bad, and it's illegal to add something other than template specializations to `std`... To solve this, you need to add a specialization of `adl_serializer` to the `nlohmann` namespace, here's an example: @@ -651,7 +651,7 @@ namespace nlohmann { if (j.is_null()) { opt = boost::none; } else { - opt = j.get(); // same as above, but with + opt = j.get(); // same as above, but with // adl_serializer::from_json } } @@ -669,7 +669,7 @@ struct move_only_type { move_only_type(int ii): i(ii) {} move_only_type(const move_only_type&) = delete; move_only_type(move_only_type&&) = default; - + int i; }; @@ -681,7 +681,7 @@ namespace nlohmann { static move_only_type from_json(const json& j) { return {j.get()}; } - + // Here's the catch! You must provide a to_json method! Otherwise you // will not be able to convert move_only_type to json, since you fully // specialized adl_serializer on that type @@ -698,9 +698,9 @@ Yes. You might want to take a look at [`unit-udt.cpp`](https://github.com/nlohma If you write your own serializer, you'll need to do a few things: -* use a different `basic_json` alias than `nlohmann::json` (the last template parameter of `basic_json` is the `JSONSerializer`) -* use your `basic_json` alias (or a template parameter) in all your `to_json`/`from_json` methods -* use `nlohmann::to_json` and `nlohmann::from_json` when you need ADL +- use a different `basic_json` alias than `nlohmann::json` (the last template parameter of `basic_json` is the `JSONSerializer`) +- use your `basic_json` alias (or a template parameter) in all your `to_json`/`from_json` methods +- use `nlohmann::to_json` and `nlohmann::from_json` when you need ADL Here is an example, without simplifications, that only accepts types with a size <= 32, and uses ADL. @@ -716,7 +716,7 @@ struct less_than_32_serializer { // this is where the magic happens to_json(j, value); } - + template static void from_json(const BasicJsonType& j, T& value) { // same thing here @@ -738,7 +738,7 @@ struct bad_serializer // if BasicJsonType::json_serializer == bad_serializer ... oops! j = value; } - + template static void to_json(const BasicJsonType& j, T& value) { // this calls BasicJsonType::json_serializer::from_json(j, value); @@ -798,13 +798,13 @@ 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. - Android defaults to using very old compilers and C++ libraries. To fix this, add the following to your `Application.mk`. This will switch to the LLVM C++ library, the Clang compiler, and enable C++11 and other features disabled by default. - + ``` APP_STL := c++_shared NDK_TOOLCHAIN_VERSION := clang3.6 APP_CPPFLAGS += -frtti -fexceptions ``` - + The code compiles successfully with [Android NDK](https://developer.android.com/ndk/index.html?hl=ml), Revision 9 - 11 (and possibly later) and [CrystaX's Android NDK](https://www.crystax.net/en/android/ndk) version 10. - For GCC running on MinGW or Android SDK, the error `'to_string' is not a member of 'std'` (or similarly, for `strtod`) may occur. Note this is not an issue with the code, but rather with the compiler itself. On Android, see above to build with a newer environment. For MinGW, please refer to [this site](http://tehsausage.com/mingw-to-string) and [this discussion](https://github.com/nlohmann/json/issues/136) for information on how to fix this bug. For Android NDK using `APP_STL := gnustl_static`, please refer to [this discussion](https://github.com/nlohmann/json/issues/219). @@ -833,7 +833,7 @@ The following compilers are currently used in continuous integration at [Travis] | Clang Xcode 9.0 | Darwin Kernel Version 16.7.0 (macOS 10.12.6) | Apple LLVM version 9.0.0 (clang-900.0.37) | | Clang Xcode 9.1 | Darwin Kernel Version 16.7.0 (macOS 10.12.6) | Apple LLVM version 9.0.0 (clang-900.0.38) | | Clang Xcode 9.2 | Darwin Kernel Version 16.7.0 (macOS 10.12.6) | Apple LLVM version 8.1.0 (clang-900.0.39.2) | -| Visual Studio 14 2015 | Windows Server 2012 R2 (x64) | Microsoft (R) Build Engine version 14.0.25420.1, MSVC 19.0.24215.1 | +| Visual Studio 14 2015 | Windows Server 2012 R2 (x64) | Microsoft (R) Build Engine version 14.0.25420.1, MSVC 19.0.24215.1 | | Visual Studio 2017 | Windows Server 2016 | Microsoft (R) Build Engine version 15.5.180.51428, MSVC 19.12.25830.2 | ## License @@ -896,7 +896,7 @@ I deeply appreciate the help of the following people. - [Corbin Hughes](https://github.com/nibroc) fixed some typos in the contribution guidelines. - [twelsby](https://github.com/twelsby) fixed the array subscript operator, an issue that failed the MSVC build, and floating-point parsing/dumping. He further added support for unsigned integer numbers and implemented better roundtrip support for parsed numbers. - [Volker Diels-Grabsch](https://github.com/vog) fixed a link in the README file. -- [msm-](https://github.com/msm-) added support for American Fuzzy Lop. +- [msm-](https://github.com/msm-) added support for American Fuzzy Lop. - [Annihil](https://github.com/Annihil) fixed an example in the README file. - [Themercee](https://github.com/Themercee) noted a wrong URL in the README file. - [Lv Zheng](https://github.com/lv-zheng) fixed a namespace issue with `int64_t` and `uint64_t`. @@ -973,6 +973,9 @@ I deeply appreciate the help of the following people. - [Patrik Huber](https://github.com/patrikhuber) fixed links in the README file. - [johnfb](https://github.com/johnfb) found a bug in the implementation of CBOR's indefinite length strings. - [Paul Fultz II](https://github.com/pfultz2) added a note on the cget package manager. +- [Wilson Lin](https://github.com/wla80) made the integration section of the README more concise. +- [RalfBielig](https://github.com/ralfbielig) detected and fixed a memory leak in the parser callback. +- [agrianius](https://github.com/agrianius) allowed to dump JSON to an alternative string type Thanks a lot for helping out! Please [let me know](mailto:mail@nlohmann.me) if I forgot someone. @@ -1002,7 +1005,7 @@ The library itself contains of a single header file licensed under the MIT licen - [**send_to_wandbox**](https://github.com/nlohmann/json/blob/develop/doc/scripts/send_to_wandbox.py) to send code examples to [Wandbox](http://melpon.org/wandbox) - [**Travis**](https://travis-ci.org) for [continuous integration](https://travis-ci.org/nlohmann/json) on Linux and macOS - [**Valgrind**](http://valgrind.org) to check for correct memory management -- [**Wandbox**](http://melpon.org/wandbox) for [online examples](https://wandbox.org/permlink/DfWUb7e2q2USw0Q6) +- [**Wandbox**](http://melpon.org/wandbox) for [online examples](https://wandbox.org/permlink/TarF5pPn9NtHQjhf) ## Projects using JSON for Modern C++ diff --git a/doc/Doxyfile b/doc/Doxyfile index fae02e76..977e4193 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -5,7 +5,7 @@ #--------------------------------------------------------------------------- DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = "JSON for Modern C++" -PROJECT_NUMBER = 3.1.1 +PROJECT_NUMBER = 3.1.2 PROJECT_BRIEF = PROJECT_LOGO = OUTPUT_DIRECTORY = . diff --git a/doc/avatars.png b/doc/avatars.png index de5ae2a9..00241908 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 8dfeb860..45b4cfb0 100644 --- a/doc/examples/README.link +++ b/doc/examples/README.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/meta.output b/doc/examples/meta.output index 4748791a..3c4bf323 100644 --- a/doc/examples/meta.output +++ b/doc/examples/meta.output @@ -11,7 +11,7 @@ "version": { "major": 3, "minor": 1, - "patch": 1, - "string": "3.1.1" + "patch": 2, + "string": "3.1.2" } } diff --git a/doc/index.md b/doc/index.md index 5d6a92d5..b3d61144 100644 --- a/doc/index.md +++ b/doc/index.md @@ -304,4 +304,4 @@ Note that this table only lists those exceptions thrown due to the type. For ins @author [Niels Lohmann](http://nlohmann.me) @see https://github.com/nlohmann/json to download the source code -@version 3.1.1 +@version 3.1.2 diff --git a/doc/json.gif b/doc/json.gif index ab3fc8b8..7d2d3c7d 100644 Binary files a/doc/json.gif and b/doc/json.gif differ diff --git a/include/nlohmann/detail/input/lexer.hpp b/include/nlohmann/detail/input/lexer.hpp index 75001652..98cc1b69 100644 --- a/include/nlohmann/detail/input/lexer.hpp +++ b/include/nlohmann/detail/input/lexer.hpp @@ -32,6 +32,7 @@ class lexer using number_integer_t = typename BasicJsonType::number_integer_t; using number_unsigned_t = typename BasicJsonType::number_unsigned_t; using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; public: /// token types for the parser @@ -1130,7 +1131,7 @@ scan_number_done: } /// return current string value (implicitly resets the token; useful only once) - std::string move_string() + string_t&& move_string() { return std::move(token_buffer); } @@ -1260,7 +1261,7 @@ scan_number_done: std::vector token_string {}; /// buffer for variable-length tokens (numbers, strings) - std::string token_buffer {}; + string_t token_buffer {}; /// a description of occurred lexer errors const char* error_message = ""; diff --git a/include/nlohmann/detail/input/parser.hpp b/include/nlohmann/detail/input/parser.hpp index 63e8541f..e58aaaf9 100644 --- a/include/nlohmann/detail/input/parser.hpp +++ b/include/nlohmann/detail/input/parser.hpp @@ -32,6 +32,7 @@ class parser using number_integer_t = typename BasicJsonType::number_integer_t; using number_unsigned_t = typename BasicJsonType::number_unsigned_t; using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; using lexer_t = lexer; using token_type = typename lexer_t::token_type; @@ -175,7 +176,7 @@ class parser } // parse values - std::string key; + string_t key; BasicJsonType value; while (true) { @@ -403,6 +404,7 @@ class parser if (keep and callback and not callback(depth, parse_event_t::value, result)) { + result.m_value.destroy(result.m_type); result.m_type = value_t::discarded; } } diff --git a/include/nlohmann/detail/meta.hpp b/include/nlohmann/detail/meta.hpp index 49f1069f..b251afb6 100644 --- a/include/nlohmann/detail/meta.hpp +++ b/include/nlohmann/detail/meta.hpp @@ -233,7 +233,7 @@ struct is_compatible_complete_type { static constexpr bool value = not std::is_base_of::value and - not std::is_same::value and + not is_basic_json::value and not is_basic_json_nested_type::value and has_to_json::value; }; diff --git a/include/nlohmann/detail/output/binary_writer.hpp b/include/nlohmann/detail/output/binary_writer.hpp index 10183262..1b15bdaf 100644 --- a/include/nlohmann/detail/output/binary_writer.hpp +++ b/include/nlohmann/detail/output/binary_writer.hpp @@ -704,116 +704,126 @@ class binary_writer oa->write_characters(vec.data(), sizeof(NumberType)); } - template + // UBJSON: write number (floating point) + template::value, int>::type = 0> void write_number_with_ubjson_prefix(const NumberType n, const bool add_prefix) { - if (std::is_floating_point::value) + if (add_prefix) + { + oa->write_character(static_cast('D')); // float64 + } + write_number(n); + } + + // UBJSON: write number (unsigned integer) + template::value, int>::type = 0> + void write_number_with_ubjson_prefix(const NumberType n, + const bool add_prefix) + { + if (n <= static_cast((std::numeric_limits::max)())) { if (add_prefix) { - oa->write_character(static_cast('D')); // float64 + oa->write_character(static_cast('i')); // int8 } - write_number(n); + write_number(static_cast(n)); } - else if (std::is_unsigned::value) + else if (n <= (std::numeric_limits::max)()) { - if (n <= (std::numeric_limits::max)()) + if (add_prefix) { - if (add_prefix) - { - oa->write_character(static_cast('i')); // int8 - } - write_number(static_cast(n)); + oa->write_character(static_cast('U')); // uint8 } - else if (n <= (std::numeric_limits::max)()) + write_number(static_cast(n)); + } + else if (n <= static_cast((std::numeric_limits::max)())) + { + if (add_prefix) { - if (add_prefix) - { - oa->write_character(static_cast('U')); // uint8 - } - write_number(static_cast(n)); + oa->write_character(static_cast('I')); // int16 } - else if (n <= (std::numeric_limits::max)()) + write_number(static_cast(n)); + } + else if (n <= static_cast((std::numeric_limits::max)())) + { + if (add_prefix) { - if (add_prefix) - { - oa->write_character(static_cast('I')); // int16 - } - write_number(static_cast(n)); + oa->write_character(static_cast('l')); // int32 } - else if (n <= (std::numeric_limits::max)()) + write_number(static_cast(n)); + } + else if (n <= static_cast((std::numeric_limits::max)())) + { + if (add_prefix) { - if (add_prefix) - { - oa->write_character(static_cast('l')); // int32 - } - write_number(static_cast(n)); - } - else if (n <= (std::numeric_limits::max)()) - { - if (add_prefix) - { - oa->write_character(static_cast('L')); // int64 - } - write_number(static_cast(n)); - } - else - { - JSON_THROW(out_of_range::create(407, "number overflow serializing " + std::to_string(n))); + oa->write_character(static_cast('L')); // int64 } + write_number(static_cast(n)); } else { - if ((std::numeric_limits::min)() <= n and n <= (std::numeric_limits::max)()) - { - if (add_prefix) - { - oa->write_character(static_cast('i')); // int8 - } - write_number(static_cast(n)); - } - else if ((std::numeric_limits::min)() <= n and n <= (std::numeric_limits::max)()) - { - if (add_prefix) - { - oa->write_character(static_cast('U')); // uint8 - } - write_number(static_cast(n)); - } - else if ((std::numeric_limits::min)() <= n and n <= (std::numeric_limits::max)()) - { - if (add_prefix) - { - oa->write_character(static_cast('I')); // int16 - } - write_number(static_cast(n)); - } - else if ((std::numeric_limits::min)() <= n and n <= (std::numeric_limits::max)()) - { - if (add_prefix) - { - oa->write_character(static_cast('l')); // int32 - } - write_number(static_cast(n)); - } - else if ((std::numeric_limits::min)() <= n and n <= (std::numeric_limits::max)()) - { - if (add_prefix) - { - oa->write_character(static_cast('L')); // int64 - } - write_number(static_cast(n)); - } - // LCOV_EXCL_START - else - { - JSON_THROW(out_of_range::create(407, "number overflow serializing " + std::to_string(n))); - } - // LCOV_EXCL_STOP + JSON_THROW(out_of_range::create(407, "number overflow serializing " + std::to_string(n))); } } + // UBJSON: write number (signed integer) + template::value and + not std::is_floating_point::value, int>::type = 0> + void write_number_with_ubjson_prefix(const NumberType n, + const bool add_prefix) + { + if ((std::numeric_limits::min)() <= n and n <= (std::numeric_limits::max)()) + { + if (add_prefix) + { + oa->write_character(static_cast('i')); // int8 + } + write_number(static_cast(n)); + } + else if (static_cast((std::numeric_limits::min)()) <= n and n <= static_cast((std::numeric_limits::max)())) + { + if (add_prefix) + { + oa->write_character(static_cast('U')); // uint8 + } + write_number(static_cast(n)); + } + else if ((std::numeric_limits::min)() <= n and n <= (std::numeric_limits::max)()) + { + if (add_prefix) + { + oa->write_character(static_cast('I')); // int16 + } + write_number(static_cast(n)); + } + else if ((std::numeric_limits::min)() <= n and n <= (std::numeric_limits::max)()) + { + if (add_prefix) + { + oa->write_character(static_cast('l')); // int32 + } + write_number(static_cast(n)); + } + else if ((std::numeric_limits::min)() <= n and n <= (std::numeric_limits::max)()) + { + if (add_prefix) + { + oa->write_character(static_cast('L')); // int64 + } + write_number(static_cast(n)); + } + // LCOV_EXCL_START + else + { + JSON_THROW(out_of_range::create(407, "number overflow serializing " + std::to_string(n))); + } + // LCOV_EXCL_STOP + } + /*! @brief determine the type prefix of container values diff --git a/include/nlohmann/detail/output/output_adapters.hpp b/include/nlohmann/detail/output/output_adapters.hpp index fe9e1b36..ff86a6e1 100644 --- a/include/nlohmann/detail/output/output_adapters.hpp +++ b/include/nlohmann/detail/output/output_adapters.hpp @@ -68,11 +68,11 @@ class output_stream_adapter : public output_adapter_protocol }; /// output adapter for basic_string -template +template> class output_string_adapter : public output_adapter_protocol { public: - explicit output_string_adapter(std::basic_string& s) : str(s) {} + explicit output_string_adapter(StringType& s) : str(s) {} void write_character(CharType c) override { @@ -85,10 +85,10 @@ class output_string_adapter : public output_adapter_protocol } private: - std::basic_string& str; + StringType& str; }; -template +template> class output_adapter { public: @@ -98,8 +98,8 @@ class output_adapter output_adapter(std::basic_ostream& s) : oa(std::make_shared>(s)) {} - output_adapter(std::basic_string& s) - : oa(std::make_shared>(s)) {} + output_adapter(StringType& s) + : oa(std::make_shared>(s)) {} operator output_adapter_t() { diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index f92729f3..7ecf631f 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ -| | |__ | | | | | | version 3.1.1 +| | |__ | | | | | | version 3.1.2 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . @@ -31,7 +31,7 @@ SOFTWARE. #define NLOHMANN_JSON_VERSION_MAJOR 3 #define NLOHMANN_JSON_VERSION_MINOR 1 -#define NLOHMANN_JSON_VERSION_PATCH 1 +#define NLOHMANN_JSON_VERSION_PATCH 2 #include // all_of, find, for_each #include // assert @@ -937,7 +937,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.1.1")); // LCOV_EXCL_LINE + JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.1.2")); // LCOV_EXCL_LINE } break; } @@ -1207,6 +1207,7 @@ class basic_json - @a CompatibleType is not derived from `std::istream`, - @a CompatibleType is not @ref basic_json (to avoid hijacking copy/move constructors), + - @a CompatibleType is not a different @ref basic_json type (i.e. with different template arguments) - @a CompatibleType is not a @ref basic_json nested type (e.g., @ref json_pointer, @ref iterator, etc ...) - @ref @ref json_serializer has a @@ -1242,6 +1243,78 @@ class basic_json assert_invariant(); } + /*! + @brief create a JSON value from an existing one + + This is a constructor for existing @ref basic_json types. + It does not hijack copy/move constructors, since the parameter has different + template arguments than the current ones. + + The constructor tries to convert the internal @ref m_value of the parameter. + + @tparam BasicJsonType a type such that: + - @a BasicJsonType is a @ref basic_json type. + - @a BasicJsonType has different template arguments than @ref basic_json_t. + + @param[in] val the @ref basic_json value to be converted. + + @complexity Usually linear in the size of the passed @a val, also + depending on the implementation of the called `to_json()` + method. + + @exceptionsafety Depends on the called constructor. For types directly + supported by the library (i.e., all types for which no `to_json()` function + was provided), strong guarantee holds: if an exception is thrown, there are + no changes to any JSON value. + + @since version 3.1.2 + */ + template ::value and not std::is_same::value, int> = 0> + basic_json(const BasicJsonType& val) + { + using other_boolean_t = typename BasicJsonType::boolean_t; + using other_number_float_t = typename BasicJsonType::number_float_t; + using other_number_integer_t = typename BasicJsonType::number_integer_t; + using other_number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using other_string_t = typename BasicJsonType::string_t; + using other_object_t = typename BasicJsonType::object_t; + using other_array_t = typename BasicJsonType::array_t; + + switch (val.type()) + { + case value_t::boolean: + JSONSerializer::to_json(*this, val.template get()); + break; + case value_t::number_float: + JSONSerializer::to_json(*this, val.template get()); + break; + case value_t::number_integer: + JSONSerializer::to_json(*this, val.template get()); + break; + case value_t::number_unsigned: + JSONSerializer::to_json(*this, val.template get()); + break; + case value_t::string: + JSONSerializer::to_json(*this, val.template get_ref()); + break; + case value_t::object: + JSONSerializer::to_json(*this, val.template get_ref()); + break; + case value_t::array: + JSONSerializer::to_json(*this, val.template get_ref()); + break; + case value_t::null: + *this = nullptr; + break; + case value_t::discarded: + m_type = value_t::discarded; + break; + } + assert_invariant(); + } + /*! @brief create a container (array or object) from an initializer list @@ -1874,7 +1947,7 @@ class basic_json const bool ensure_ascii = false) const { string_t result; - serializer s(detail::output_adapter(result), indent_char); + serializer s(detail::output_adapter(result), indent_char); if (indent >= 0) { @@ -2414,6 +2487,29 @@ class basic_json return *this; } + /*! + @brief get special-case overload + + This overloads converts the current @ref basic_json in a different + @ref basic_json type + + @tparam BasicJsonType == @ref basic_json + + @return a copy of *this, converted into @tparam BasicJsonType + + @complexity Depending on the implementation of the called `from_json()` + method. + + @since version 3.1.2 + */ + template::value and + detail::is_basic_json::value, int> = 0> + BasicJsonType get() const + { + return *this; + } + /*! @brief get a value (explicit) @@ -2455,7 +2551,7 @@ class basic_json */ template, detail::enable_if_t < - not std::is_same::value and + not detail::is_basic_json::value and detail::has_from_json::value and not detail::has_non_default_from_json::value, int> = 0> @@ -2721,7 +2817,8 @@ class basic_json template < typename ValueType, typename std::enable_if < not std::is_pointer::value and not std::is_same>::value and - not std::is_same::value + not std::is_same::value and + not detail::is_basic_json::value #ifndef _MSC_VER // fix for issue #167 operator<< ambiguity under VS2015 and not std::is_same>::value #endif @@ -5179,7 +5276,7 @@ class basic_json // passed iterators must belong to objects if (JSON_UNLIKELY(not first.m_object->is_object() - or not first.m_object->is_object())) + or not last.m_object->is_object())) { JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects")); } diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 3dcb834b..6b6655af 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ -| | |__ | | | | | | version 3.1.1 +| | |__ | | | | | | version 3.1.2 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . @@ -31,7 +31,7 @@ SOFTWARE. #define NLOHMANN_JSON_VERSION_MAJOR 3 #define NLOHMANN_JSON_VERSION_MINOR 1 -#define NLOHMANN_JSON_VERSION_PATCH 1 +#define NLOHMANN_JSON_VERSION_PATCH 2 #include // all_of, find, for_each #include // assert @@ -466,7 +466,7 @@ struct is_compatible_complete_type { static constexpr bool value = not std::is_base_of::value and - not std::is_same::value and + not is_basic_json::value and not is_basic_json_nested_type::value and has_to_json::value; }; @@ -1871,6 +1871,7 @@ class lexer using number_integer_t = typename BasicJsonType::number_integer_t; using number_unsigned_t = typename BasicJsonType::number_unsigned_t; using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; public: /// token types for the parser @@ -2969,7 +2970,7 @@ scan_number_done: } /// return current string value (implicitly resets the token; useful only once) - std::string move_string() + string_t&& move_string() { return std::move(token_buffer); } @@ -3099,7 +3100,7 @@ scan_number_done: std::vector token_string {}; /// buffer for variable-length tokens (numbers, strings) - std::string token_buffer {}; + string_t token_buffer {}; /// a description of occurred lexer errors const char* error_message = ""; @@ -3155,6 +3156,7 @@ class parser using number_integer_t = typename BasicJsonType::number_integer_t; using number_unsigned_t = typename BasicJsonType::number_unsigned_t; using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; using lexer_t = lexer; using token_type = typename lexer_t::token_type; @@ -3298,7 +3300,7 @@ class parser } // parse values - std::string key; + string_t key; BasicJsonType value; while (true) { @@ -3526,6 +3528,7 @@ class parser if (keep and callback and not callback(depth, parse_event_t::value, result)) { + result.m_value.destroy(result.m_type); result.m_type = value_t::discarded; } } @@ -4776,11 +4779,11 @@ class output_stream_adapter : public output_adapter_protocol }; /// output adapter for basic_string -template +template> class output_string_adapter : public output_adapter_protocol { public: - explicit output_string_adapter(std::basic_string& s) : str(s) {} + explicit output_string_adapter(StringType& s) : str(s) {} void write_character(CharType c) override { @@ -4793,10 +4796,10 @@ class output_string_adapter : public output_adapter_protocol } private: - std::basic_string& str; + StringType& str; }; -template +template> class output_adapter { public: @@ -4806,8 +4809,8 @@ class output_adapter output_adapter(std::basic_ostream& s) : oa(std::make_shared>(s)) {} - output_adapter(std::basic_string& s) - : oa(std::make_shared>(s)) {} + output_adapter(StringType& s) + : oa(std::make_shared>(s)) {} operator output_adapter_t() { @@ -6909,116 +6912,126 @@ class binary_writer oa->write_characters(vec.data(), sizeof(NumberType)); } - template + // UBJSON: write number (floating point) + template::value, int>::type = 0> void write_number_with_ubjson_prefix(const NumberType n, const bool add_prefix) { - if (std::is_floating_point::value) + if (add_prefix) + { + oa->write_character(static_cast('D')); // float64 + } + write_number(n); + } + + // UBJSON: write number (unsigned integer) + template::value, int>::type = 0> + void write_number_with_ubjson_prefix(const NumberType n, + const bool add_prefix) + { + if (n <= static_cast((std::numeric_limits::max)())) { if (add_prefix) { - oa->write_character(static_cast('D')); // float64 + oa->write_character(static_cast('i')); // int8 } - write_number(n); + write_number(static_cast(n)); } - else if (std::is_unsigned::value) + else if (n <= (std::numeric_limits::max)()) { - if (n <= (std::numeric_limits::max)()) + if (add_prefix) { - if (add_prefix) - { - oa->write_character(static_cast('i')); // int8 - } - write_number(static_cast(n)); + oa->write_character(static_cast('U')); // uint8 } - else if (n <= (std::numeric_limits::max)()) + write_number(static_cast(n)); + } + else if (n <= static_cast((std::numeric_limits::max)())) + { + if (add_prefix) { - if (add_prefix) - { - oa->write_character(static_cast('U')); // uint8 - } - write_number(static_cast(n)); + oa->write_character(static_cast('I')); // int16 } - else if (n <= (std::numeric_limits::max)()) + write_number(static_cast(n)); + } + else if (n <= static_cast((std::numeric_limits::max)())) + { + if (add_prefix) { - if (add_prefix) - { - oa->write_character(static_cast('I')); // int16 - } - write_number(static_cast(n)); + oa->write_character(static_cast('l')); // int32 } - else if (n <= (std::numeric_limits::max)()) + write_number(static_cast(n)); + } + else if (n <= static_cast((std::numeric_limits::max)())) + { + if (add_prefix) { - if (add_prefix) - { - oa->write_character(static_cast('l')); // int32 - } - write_number(static_cast(n)); - } - else if (n <= (std::numeric_limits::max)()) - { - if (add_prefix) - { - oa->write_character(static_cast('L')); // int64 - } - write_number(static_cast(n)); - } - else - { - JSON_THROW(out_of_range::create(407, "number overflow serializing " + std::to_string(n))); + oa->write_character(static_cast('L')); // int64 } + write_number(static_cast(n)); } else { - if ((std::numeric_limits::min)() <= n and n <= (std::numeric_limits::max)()) - { - if (add_prefix) - { - oa->write_character(static_cast('i')); // int8 - } - write_number(static_cast(n)); - } - else if ((std::numeric_limits::min)() <= n and n <= (std::numeric_limits::max)()) - { - if (add_prefix) - { - oa->write_character(static_cast('U')); // uint8 - } - write_number(static_cast(n)); - } - else if ((std::numeric_limits::min)() <= n and n <= (std::numeric_limits::max)()) - { - if (add_prefix) - { - oa->write_character(static_cast('I')); // int16 - } - write_number(static_cast(n)); - } - else if ((std::numeric_limits::min)() <= n and n <= (std::numeric_limits::max)()) - { - if (add_prefix) - { - oa->write_character(static_cast('l')); // int32 - } - write_number(static_cast(n)); - } - else if ((std::numeric_limits::min)() <= n and n <= (std::numeric_limits::max)()) - { - if (add_prefix) - { - oa->write_character(static_cast('L')); // int64 - } - write_number(static_cast(n)); - } - // LCOV_EXCL_START - else - { - JSON_THROW(out_of_range::create(407, "number overflow serializing " + std::to_string(n))); - } - // LCOV_EXCL_STOP + JSON_THROW(out_of_range::create(407, "number overflow serializing " + std::to_string(n))); } } + // UBJSON: write number (signed integer) + template::value and + not std::is_floating_point::value, int>::type = 0> + void write_number_with_ubjson_prefix(const NumberType n, + const bool add_prefix) + { + if ((std::numeric_limits::min)() <= n and n <= (std::numeric_limits::max)()) + { + if (add_prefix) + { + oa->write_character(static_cast('i')); // int8 + } + write_number(static_cast(n)); + } + else if (static_cast((std::numeric_limits::min)()) <= n and n <= static_cast((std::numeric_limits::max)())) + { + if (add_prefix) + { + oa->write_character(static_cast('U')); // uint8 + } + write_number(static_cast(n)); + } + else if ((std::numeric_limits::min)() <= n and n <= (std::numeric_limits::max)()) + { + if (add_prefix) + { + oa->write_character(static_cast('I')); // int16 + } + write_number(static_cast(n)); + } + else if ((std::numeric_limits::min)() <= n and n <= (std::numeric_limits::max)()) + { + if (add_prefix) + { + oa->write_character(static_cast('l')); // int32 + } + write_number(static_cast(n)); + } + else if ((std::numeric_limits::min)() <= n and n <= (std::numeric_limits::max)()) + { + if (add_prefix) + { + oa->write_character(static_cast('L')); // int64 + } + write_number(static_cast(n)); + } + // LCOV_EXCL_START + else + { + JSON_THROW(out_of_range::create(407, "number overflow serializing " + std::to_string(n))); + } + // LCOV_EXCL_STOP + } + /*! @brief determine the type prefix of container values @@ -10535,7 +10548,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.1.1")); // LCOV_EXCL_LINE + JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.1.2")); // LCOV_EXCL_LINE } break; } @@ -10805,6 +10818,7 @@ class basic_json - @a CompatibleType is not derived from `std::istream`, - @a CompatibleType is not @ref basic_json (to avoid hijacking copy/move constructors), + - @a CompatibleType is not a different @ref basic_json type (i.e. with different template arguments) - @a CompatibleType is not a @ref basic_json nested type (e.g., @ref json_pointer, @ref iterator, etc ...) - @ref @ref json_serializer has a @@ -10840,6 +10854,78 @@ class basic_json assert_invariant(); } + /*! + @brief create a JSON value from an existing one + + This is a constructor for existing @ref basic_json types. + It does not hijack copy/move constructors, since the parameter has different + template arguments than the current ones. + + The constructor tries to convert the internal @ref m_value of the parameter. + + @tparam BasicJsonType a type such that: + - @a BasicJsonType is a @ref basic_json type. + - @a BasicJsonType has different template arguments than @ref basic_json_t. + + @param[in] val the @ref basic_json value to be converted. + + @complexity Usually linear in the size of the passed @a val, also + depending on the implementation of the called `to_json()` + method. + + @exceptionsafety Depends on the called constructor. For types directly + supported by the library (i.e., all types for which no `to_json()` function + was provided), strong guarantee holds: if an exception is thrown, there are + no changes to any JSON value. + + @since version 3.1.2 + */ + template ::value and not std::is_same::value, int> = 0> + basic_json(const BasicJsonType& val) + { + using other_boolean_t = typename BasicJsonType::boolean_t; + using other_number_float_t = typename BasicJsonType::number_float_t; + using other_number_integer_t = typename BasicJsonType::number_integer_t; + using other_number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using other_string_t = typename BasicJsonType::string_t; + using other_object_t = typename BasicJsonType::object_t; + using other_array_t = typename BasicJsonType::array_t; + + switch (val.type()) + { + case value_t::boolean: + JSONSerializer::to_json(*this, val.template get()); + break; + case value_t::number_float: + JSONSerializer::to_json(*this, val.template get()); + break; + case value_t::number_integer: + JSONSerializer::to_json(*this, val.template get()); + break; + case value_t::number_unsigned: + JSONSerializer::to_json(*this, val.template get()); + break; + case value_t::string: + JSONSerializer::to_json(*this, val.template get_ref()); + break; + case value_t::object: + JSONSerializer::to_json(*this, val.template get_ref()); + break; + case value_t::array: + JSONSerializer::to_json(*this, val.template get_ref()); + break; + case value_t::null: + *this = nullptr; + break; + case value_t::discarded: + m_type = value_t::discarded; + break; + } + assert_invariant(); + } + /*! @brief create a container (array or object) from an initializer list @@ -11472,7 +11558,7 @@ class basic_json const bool ensure_ascii = false) const { string_t result; - serializer s(detail::output_adapter(result), indent_char); + serializer s(detail::output_adapter(result), indent_char); if (indent >= 0) { @@ -12012,6 +12098,29 @@ class basic_json return *this; } + /*! + @brief get special-case overload + + This overloads converts the current @ref basic_json in a different + @ref basic_json type + + @tparam BasicJsonType == @ref basic_json + + @return a copy of *this, converted into @tparam BasicJsonType + + @complexity Depending on the implementation of the called `from_json()` + method. + + @since version 3.1.2 + */ + template::value and + detail::is_basic_json::value, int> = 0> + BasicJsonType get() const + { + return *this; + } + /*! @brief get a value (explicit) @@ -12053,7 +12162,7 @@ class basic_json */ template, detail::enable_if_t < - not std::is_same::value and + not detail::is_basic_json::value and detail::has_from_json::value and not detail::has_non_default_from_json::value, int> = 0> @@ -12319,7 +12428,8 @@ class basic_json template < typename ValueType, typename std::enable_if < not std::is_pointer::value and not std::is_same>::value and - not std::is_same::value + not std::is_same::value and + not detail::is_basic_json::value #ifndef _MSC_VER // fix for issue #167 operator<< ambiguity under VS2015 and not std::is_same>::value #endif @@ -14777,7 +14887,7 @@ class basic_json // passed iterators must belong to objects if (JSON_UNLIKELY(not first.m_object->is_object() - or not first.m_object->is_object())) + or not last.m_object->is_object())) { JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects")); } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index d53d5c4b..e5f6dc55 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -104,6 +104,7 @@ foreach(file ${files}) target_compile_definitions(${testcase} PRIVATE CATCH_CONFIG_FAST_COMPILE) target_include_directories(${testcase} PRIVATE "thirdparty/catch") + target_include_directories(${testcase} PRIVATE "thirdparty/fifo_map") target_include_directories(${testcase} PRIVATE ${NLOHMANN_JSON_INCLUDE_BUILD_DIR}) target_link_libraries(${testcase} ${NLOHMANN_JSON_TARGET_NAME}) diff --git a/test/Makefile b/test/Makefile index 4dc39916..f373451f 100644 --- a/test/Makefile +++ b/test/Makefile @@ -4,11 +4,12 @@ # additional flags CXXFLAGS += -std=c++11 -Wall -Wextra -pedantic -Wcast-align -Wcast-qual -Wno-ctor-dtor-privacy -Wdisabled-optimization -Wformat=2 -Winit-self -Wmissing-declarations -Wmissing-include-dirs -Wold-style-cast -Woverloaded-virtual -Wredundant-decls -Wshadow -Wsign-conversion -Wsign-promo -Wstrict-overflow=5 -Wswitch -Wundef -Wno-unused -Wnon-virtual-dtor -Wreorder -Wdeprecated -Wno-float-equal -CPPFLAGS += -I ../single_include -I . -I thirdparty/catch -DCATCH_CONFIG_FAST_COMPILE +CPPFLAGS += -I ../single_include -I . -I thirdparty/catch -I thirdparty/fifo_map -DCATCH_CONFIG_FAST_COMPILE SOURCES = src/unit.cpp \ src/unit-algorithms.cpp \ src/unit-allocator.cpp \ + src/unit-alt-string.cpp \ src/unit-capacity.cpp \ src/unit-cbor.cpp \ src/unit-class_const_iterator.cpp \ diff --git a/test/src/fuzzer-driver_afl.cpp b/test/src/fuzzer-driver_afl.cpp index 56cb2503..bc8b3e76 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.1.1 +| | |__ | | | | | | version 3.1.2 |_____|_____|_____|_|___| 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 840e5b2d..0520ae7c 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.1.1 +| | |__ | | | | | | version 3.1.2 |_____|_____|_____|_|___| 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 46c522b2..2d13c26b 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.1.1 +| | |__ | | | | | | version 3.1.2 |_____|_____|_____|_|___| 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 65d3b13b..6f98409f 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.1.1 +| | |__ | | | | | | version 3.1.2 |_____|_____|_____|_|___| 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 be84fd05..1d7c936c 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.1.1 +| | |__ | | | | | | version 3.1.2 |_____|_____|_____|_|___| 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 55a21533..6579c4a5 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.1.1 +| | |__ | | | | | | version 3.1.2 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-allocator.cpp b/test/src/unit-allocator.cpp index 89a83853..debe69ad 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.1.1 +| | |__ | | | | | | version 3.1.2 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-alt-string.cpp b/test/src/unit-alt-string.cpp new file mode 100644 index 00000000..36c8b83b --- /dev/null +++ b/test/src/unit-alt-string.cpp @@ -0,0 +1,212 @@ +/* + __ _____ _____ _____ + __| | __| | | | JSON for Modern C++ (test suite) +| | |__ | | | | | | version 3.1.2 +|_____|_____|_____|_|___| https://github.com/nlohmann/json + +Licensed under the MIT License . +Copyright (c) 2018 Vitaliy Manushkin . + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include "catch.hpp" + +#include +#include +#include + +/* + * This is virtually a string class. + * It covers std::string under the hood. + */ +class alt_string +{ + public: + using value_type = std::string::value_type; + + alt_string(const char* str): str_impl(str) {} + alt_string(const char* str, std::size_t count): str_impl(str, count) {} + alt_string(size_t count, char chr): str_impl(count, chr) {} + alt_string() = default; + + template + alt_string& append(TParams&& ...params) + { + str_impl.append(std::forward(params)...); + return *this; + } + + void push_back(char c) + { + str_impl.push_back(c); + } + + template + bool operator==(op_type&& op) const + { + return str_impl == op; + } + + template + bool operator!=(op_type&& op) const + { + return str_impl != op; + } + + std::size_t size() const noexcept + { + return str_impl.size(); + } + + void resize (std::size_t n) + { + str_impl.resize(n); + } + + void resize (std::size_t n, char c) + { + str_impl.resize(n, c); + } + + template + bool operator<(op_type&& op) const + { + return str_impl < op; + } + + bool operator<(const alt_string& op) const + { + return str_impl < op.str_impl; + } + + const char* c_str() const + { + return str_impl.c_str(); + } + + char& operator[](std::size_t index) + { + return str_impl[index]; + } + + const char& operator[](std::size_t index) const + { + return str_impl[index]; + } + + char& back() + { + return str_impl.back(); + } + + const char& back() const + { + return str_impl.back(); + } + + void clear() + { + str_impl.clear(); + } + + const value_type* data() + { + return str_impl.data(); + } + + private: + std::string str_impl; +}; + + +using alt_json = nlohmann::basic_json < + std::map, + std::vector, + alt_string, + bool, + std::int64_t, + std::uint64_t, + double, + std::allocator, + nlohmann::adl_serializer >; + + + +TEST_CASE("alternative string type") +{ + SECTION("dump") + { + { + alt_json doc; + doc["pi"] = 3.141; + alt_string dump = doc.dump(); + CHECK(dump == R"({"pi":3.141})"); + } + + { + alt_json doc; + doc["happy"] = true; + alt_string dump = doc.dump(); + CHECK(dump == R"({"happy":true})"); + } + + { + alt_json doc; + doc["name"] = "I'm Batman"; + alt_string dump = doc.dump(); + CHECK(dump == R"({"name":"I'm Batman"})"); + } + + { + alt_json doc; + doc["nothing"] = nullptr; + alt_string dump = doc.dump(); + CHECK(dump == R"({"nothing":null})"); + } + + { + alt_json doc; + doc["answer"]["everything"] = 42; + alt_string dump = doc.dump(); + CHECK(dump == R"({"answer":{"everything":42}})"); + } + + { + alt_json doc; + doc["list"] = { 1, 0, 2 }; + alt_string dump = doc.dump(); + CHECK(dump == R"({"list":[1,0,2]})"); + } + + { + alt_json doc; + doc["list"] = { 1, 0, 2 }; + alt_string dump = doc.dump(); + CHECK(dump == R"({"list":[1,0,2]})"); + } + } + + SECTION("parse") + { + auto doc = alt_json::parse("{\"foo\": \"bar\"}"); + alt_string dump = doc.dump(); + CHECK(dump == R"({"foo":"bar"})"); + } +} diff --git a/test/src/unit-capacity.cpp b/test/src/unit-capacity.cpp index 8b36ca81..47ac03cc 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.1.1 +| | |__ | | | | | | version 3.1.2 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-cbor.cpp b/test/src/unit-cbor.cpp index 90e1db92..6b9eac52 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.1.1 +| | |__ | | | | | | version 3.1.2 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-class_const_iterator.cpp b/test/src/unit-class_const_iterator.cpp index b7e225d5..8319fef5 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.1.1 +| | |__ | | | | | | version 3.1.2 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-class_iterator.cpp b/test/src/unit-class_iterator.cpp index bb91310d..484a49de 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.1.1 +| | |__ | | | | | | version 3.1.2 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-class_lexer.cpp b/test/src/unit-class_lexer.cpp index 515f1ba0..164dc67d 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.1.1 +| | |__ | | | | | | version 3.1.2 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-class_parser.cpp b/test/src/unit-class_parser.cpp index 3e309469..29a948e8 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.1.1 +| | |__ | | | | | | version 3.1.2 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-comparison.cpp b/test/src/unit-comparison.cpp index f17cba6e..0659c1db 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.1.1 +| | |__ | | | | | | version 3.1.2 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-concepts.cpp b/test/src/unit-concepts.cpp index 0c8faa5f..e2aac157 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.1.1 +| | |__ | | | | | | version 3.1.2 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-constructor1.cpp b/test/src/unit-constructor1.cpp index 984900bf..35652bd8 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.1.1 +| | |__ | | | | | | version 3.1.2 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-constructor2.cpp b/test/src/unit-constructor2.cpp index 107cccfe..e36de923 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.1.1 +| | |__ | | | | | | version 3.1.2 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-convenience.cpp b/test/src/unit-convenience.cpp index a61fee72..15596032 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.1.1 +| | |__ | | | | | | version 3.1.2 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-conversions.cpp b/test/src/unit-conversions.cpp index 641b5b68..d67f5acb 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.1.1 +| | |__ | | | | | | version 3.1.2 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-deserialization.cpp b/test/src/unit-deserialization.cpp index 6e46abe3..2886f009 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.1.1 +| | |__ | | | | | | version 3.1.2 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-element_access1.cpp b/test/src/unit-element_access1.cpp index a805faf1..d06b97ca 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.1.1 +| | |__ | | | | | | version 3.1.2 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-element_access2.cpp b/test/src/unit-element_access2.cpp index 1f097490..5ea4b8a5 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.1.1 +| | |__ | | | | | | version 3.1.2 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-inspection.cpp b/test/src/unit-inspection.cpp index a486dc04..111e6ea2 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.1.1 +| | |__ | | | | | | version 3.1.2 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-items.cpp b/test/src/unit-items.cpp index 6bd79082..8f18884d 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.1.1 +| | |__ | | | | | | version 3.1.2 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-iterators1.cpp b/test/src/unit-iterators1.cpp index feaecf6d..c8125ce7 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.1.1 +| | |__ | | | | | | version 3.1.2 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-iterators2.cpp b/test/src/unit-iterators2.cpp index 08db0583..2d369881 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.1.1 +| | |__ | | | | | | version 3.1.2 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-json_patch.cpp b/test/src/unit-json_patch.cpp index 1084e63c..1a71621d 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.1.1 +| | |__ | | | | | | version 3.1.2 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-json_pointer.cpp b/test/src/unit-json_pointer.cpp index 2497dc6a..c630da56 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.1.1 +| | |__ | | | | | | version 3.1.2 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-merge_patch.cpp b/test/src/unit-merge_patch.cpp index 48e56d6b..2daaf00f 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.1.1 +| | |__ | | | | | | version 3.1.2 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-meta.cpp b/test/src/unit-meta.cpp index 2944326d..6fc84998 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.1.1 +| | |__ | | | | | | version 3.1.2 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . @@ -42,10 +42,10 @@ TEST_CASE("version information") CHECK(j["url"] == "https://github.com/nlohmann/json"); CHECK(j["version"] == json( { - {"string", "3.1.1"}, + {"string", "3.1.2"}, {"major", 3}, {"minor", 1}, - {"patch", 1} + {"patch", 2} })); CHECK(j.find("platform") != j.end()); diff --git a/test/src/unit-modifiers.cpp b/test/src/unit-modifiers.cpp index 4b0eb9ee..ada65f20 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.1.1 +| | |__ | | | | | | version 3.1.2 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-msgpack.cpp b/test/src/unit-msgpack.cpp index 404442bf..d8bdb08b 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.1.1 +| | |__ | | | | | | version 3.1.2 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-noexcept.cpp b/test/src/unit-noexcept.cpp index 1aa4abd1..4b3dcade 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.1.1 +| | |__ | | | | | | version 3.1.2 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-pointer_access.cpp b/test/src/unit-pointer_access.cpp index 3e9e486f..5670269a 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.1.1 +| | |__ | | | | | | version 3.1.2 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-readme.cpp b/test/src/unit-readme.cpp index bdcbd73e..4c163afa 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.1.1 +| | |__ | | | | | | version 3.1.2 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . @@ -152,6 +152,10 @@ TEST_CASE("README", "[hide]") j.push_back(1); j.push_back(true); + // comparison + bool x = (j == "[\"foo\", 1, true]"_json); // true + CHECK(x == true); + // iterate the array for (json::iterator it = j.begin(); it != j.end(); ++it) { @@ -168,6 +172,7 @@ TEST_CASE("README", "[hide]") const std::string tmp = j[0]; j[1] = 42; bool foo = j.at(2); + CHECK(foo == true); // other stuff j.size(); // 3 entries @@ -175,9 +180,6 @@ TEST_CASE("README", "[hide]") j.type(); // json::value_t::array j.clear(); // the array is empty again - // comparison - bool x = (j == "[\"foo\", 1, true]"_json); // true - // create an object json o; o["foo"] = 23; @@ -257,17 +259,21 @@ TEST_CASE("README", "[hide]") bool b1 = true; json jb = b1; bool b2 = jb; + CHECK(b2 == true); // numbers int i = 42; json jn = i; double f = jn; + CHECK(f == 42); // etc. std::string vs = js.get(); bool vb = jb.get(); + CHECK(vb == true); int vi = jn.get(); + CHECK(vi == 42); // etc. } diff --git a/test/src/unit-reference_access.cpp b/test/src/unit-reference_access.cpp index ce00eccb..3c92096f 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.1.1 +| | |__ | | | | | | version 3.1.2 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-regression.cpp b/test/src/unit-regression.cpp index 97bdf0c1..c4ca93d9 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.1.1 +| | |__ | | | | | | version 3.1.2 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . @@ -32,10 +32,72 @@ SOFTWARE. #include using nlohmann::json; +#include "fifo_map.hpp" + #include #include #include +///////////////////////////////////////////////////////////////////// +// for #972 +///////////////////////////////////////////////////////////////////// + +template +using my_workaround_fifo_map = nlohmann::fifo_map, A>; +using my_json = nlohmann::basic_json; + +///////////////////////////////////////////////////////////////////// +// for #977 +///////////////////////////////////////////////////////////////////// + +namespace ns +{ +struct foo +{ + int x; +}; + +template +struct foo_serializer; + +template +struct foo_serializer::value>::type> +{ + template + static void to_json(BasicJsonType& j, const T& value) + { + j = BasicJsonType{{"x", value.x}}; + } + template + static void from_json(const BasicJsonType& j, T& value) // !!! + { + nlohmann::from_json(j.at("x"), value.x); + } +}; + +template +struct foo_serializer < T, typename std::enable_if < !std::is_same::value >::type > +{ + template + static void to_json(BasicJsonType& j, const T& value) noexcept + { + ::nlohmann::to_json(j, value); + } + template + static void from_json(const BasicJsonType& j, T& value) //!!! + { + ::nlohmann::from_json(j, value); + } +}; +} + +using foo_json = nlohmann::basic_json; + +///////////////////////////////////////////////////////////////////// +// for #805 +///////////////////////////////////////////////////////////////////// + namespace { struct nocopy @@ -1436,4 +1498,103 @@ TEST_CASE("regression tests") //CHECK_THROWS_WITH(json::from_ubjson(v_ubjson), // "[json.exception.out_of_range.408] excessive object size: 8658170730974374167"); } + + SECTION("issue #972 - Segmentation fault on G++ when trying to assign json string literal to custom json type") + { + my_json foo = R"([1, 2, 3])"_json; + } + + SECTION("issue #977 - Assigning between different json types") + { + foo_json lj = ns::foo{3}; + ns::foo ff = lj; + CHECK(lj.is_object()); + CHECK(lj.size() == 1); + CHECK(lj["x"] == 3); + CHECK(ff.x == 3); + nlohmann::json nj = lj; // This line works as expected + } + + SECTION("issue #1001 - Fix memory leak during parser callback") + { + auto geojsonExample = R"( + { "type": "FeatureCollection", + "features": [ + { "type": "Feature", + "geometry": {"type": "Point", "coordinates": [102.0, 0.5]}, + "properties": {"prop0": "value0"} + }, + { "type": "Feature", + "geometry": { + "type": "LineString", + "coordinates": [ + [102.0, 0.0], [103.0, 1.0], [104.0, 0.0], [105.0, 1.0] + ] + }, + "properties": { + "prop0": "value0", + "prop1": 0.0 + } + }, + { "type": "Feature", + "geometry": { + "type": "Polygon", + "coordinates": [ + [ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0], + [100.0, 1.0], [100.0, 0.0] ] + ] + }, + "properties": { + "prop0": "value0", + "prop1": {"this": "that"} + } + } + ] + })"; + + json::parser_callback_t cb = [&](int, json::parse_event_t event, json & parsed) + { + // skip uninteresting events + if (event == json::parse_event_t::value and !parsed.is_primitive()) + { + return false; + } + + switch (event) + { + case json::parse_event_t::key: + { + return true; + } + case json::parse_event_t::value: + { + return false; + } + case json::parse_event_t::object_start: + { + return true; + } + case json::parse_event_t::object_end: + { + return false; + } + case json::parse_event_t::array_start: + { + return true; + } + case json::parse_event_t::array_end: + { + return false; + } + + default: + { + return true; + } + } + }; + + auto j = json::parse(geojsonExample, cb, true); + CHECK(j == json()); + } } diff --git a/test/src/unit-serialization.cpp b/test/src/unit-serialization.cpp index 8c8e8a4d..ebe64297 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.1.1 +| | |__ | | | | | | version 3.1.2 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-testsuites.cpp b/test/src/unit-testsuites.cpp index 2a01fba9..5f77a737 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.1.1 +| | |__ | | | | | | version 3.1.2 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-to_chars.cpp b/test/src/unit-to_chars.cpp index 13c2b467..841e164b 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.1.1 +| | |__ | | | | | | version 3.1.2 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit-ubjson.cpp b/test/src/unit-ubjson.cpp index b3c9ad57..e2f77234 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.1.1 +| | |__ | | | | | | version 3.1.2 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . @@ -152,7 +152,7 @@ TEST_CASE("UBJSON") numbers.push_back(-10000000); numbers.push_back(-100000000); numbers.push_back(-1000000000); - numbers.push_back(-2147483648); + numbers.push_back(-2147483648L); for (auto i : numbers) { CAPTURE(i); diff --git a/test/src/unit-udt.cpp b/test/src/unit-udt.cpp index f270fdc4..9cfc6e97 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.1.1 +| | |__ | | | | | | version 3.1.2 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . @@ -693,6 +693,83 @@ TEST_CASE("custom serializer that does adl by default", "[udt]") CHECK(me == cj.get()); } +TEST_CASE("different basic_json types conversions") +{ + using json = nlohmann::json; + + SECTION("null") + { + json j; + custom_json cj = j; + CHECK(cj == nullptr); + } + + SECTION("boolean") + { + json j = true; + custom_json cj = j; + CHECK(cj == true); + } + + SECTION("discarded") + { + json j(json::value_t::discarded); + custom_json cj; + CHECK_NOTHROW(cj = j); + CHECK(cj.type() == custom_json::value_t::discarded); + } + + SECTION("array") + { + json j = {1, 2, 3}; + custom_json cj = j; + CHECK((cj == std::vector {1, 2, 3})); + } + + SECTION("integer") + { + json j = 42; + custom_json cj = j; + CHECK(cj == 42); + } + + SECTION("float") + { + json j = 42.0; + custom_json cj = j; + CHECK(cj == 42.0); + } + + SECTION("unsigned") + { + json j = 42u; + custom_json cj = j; + CHECK(cj == 42u); + } + + SECTION("string") + { + json j = "forty-two"; + custom_json cj = j; + CHECK(cj == "forty-two"); + } + + SECTION("object") + { + json j = {{"forty", "two"}}; + custom_json cj = j; + auto m = j.get>(); + CHECK(cj == m); + } + + SECTION("get") + { + json j = 42; + custom_json cj = j.get(); + CHECK(cj == 42); + } +} + namespace { struct incomplete; @@ -730,6 +807,6 @@ TEST_CASE("Issue #924") // Prevent get>() to throw auto j = json::array(); - (void) j.get(); - (void) j.get>(); + CHECK_NOTHROW(j.get()); + CHECK_NOTHROW(j.get>()); } diff --git a/test/src/unit-unicode.cpp b/test/src/unit-unicode.cpp index 4c2b75e8..95925dee 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.1.1 +| | |__ | | | | | | version 3.1.2 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/src/unit.cpp b/test/src/unit.cpp index 289fd8ed..95659955 100644 --- a/test/src/unit.cpp +++ b/test/src/unit.cpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ (test suite) -| | |__ | | | | | | version 3.1.1 +| | |__ | | | | | | version 3.1.2 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . diff --git a/test/thirdparty/fifo_map/LICENSE.MIT b/test/thirdparty/fifo_map/LICENSE.MIT new file mode 100644 index 00000000..8c59cdf2 --- /dev/null +++ b/test/thirdparty/fifo_map/LICENSE.MIT @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2015-2017 Niels Lohmann + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/test/thirdparty/fifo_map/fifo_map.hpp b/test/thirdparty/fifo_map/fifo_map.hpp new file mode 100644 index 00000000..c281e3be --- /dev/null +++ b/test/thirdparty/fifo_map/fifo_map.hpp @@ -0,0 +1,530 @@ +/* +The code is licensed under the MIT License : + +Copyright (c) 2015-2017 Niels Lohmann. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifndef NLOHMANN_FIFO_MAP_HPP +#define NLOHMANN_FIFO_MAP_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/*! +@brief namespace for Niels Lohmann +@see https://github.com/nlohmann +*/ +namespace nlohmann +{ + +template +class fifo_map_compare +{ + public: + /// constructor given a pointer to a key storage + fifo_map_compare(std::unordered_map* k) : keys(k) {} + + /*! + This function compares two keys with respect to the order in which they + were added to the container. For this, the mapping keys is used. + */ + bool operator()(const Key& lhs, const Key& rhs) const + { + // look up timestamps for both keys + const auto timestamp_lhs = keys->find(lhs); + const auto timestamp_rhs = keys->find(rhs); + + if (timestamp_lhs == keys->end()) + { + // timestamp for lhs not found - cannot be smaller than for rhs + return false; + } + + if (timestamp_rhs == keys->end()) + { + // timestamp for rhs not found - timestamp for lhs is smaller + return true; + } + + // compare timestamps + return timestamp_lhs->second < timestamp_rhs->second; + } + + void add_key(const Key& key) + { + keys->insert({key, timestamp++}); + } + + void remove_key(const Key& key) + { + keys->erase(key); + } + + private: + /// pointer to a mapping from keys to insertion timestamps + std::unordered_map* keys = nullptr; + /// the next valid insertion timestamp + size_t timestamp = 1; +}; + + +template < + class Key, + class T, + class Compare = fifo_map_compare, + class Allocator = std::allocator> + > class fifo_map +{ + public: + using key_type = Key; + using mapped_type = T; + using value_type = std::pair; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using key_compare = Compare; + using allocator_type = Allocator; + using reference = value_type&; + using const_reference = const value_type&; + using pointer = typename std::allocator_traits::pointer; + using const_pointer = typename std::allocator_traits::const_pointer; + + using internal_map_type = std::map; + + using iterator = typename internal_map_type::iterator; + using const_iterator = typename internal_map_type::const_iterator; + using reverse_iterator = typename internal_map_type::reverse_iterator; + using const_reverse_iterator = typename internal_map_type::const_reverse_iterator; + + public: + /// default constructor + fifo_map() : m_keys(), m_compare(&m_keys), m_map(m_compare) {} + + /// copy constructor + fifo_map(const fifo_map &f) : m_keys(f.m_keys), m_compare(&m_keys), m_map(f.m_map.begin(), f.m_map.end(), m_compare) {} + + /// constructor for a range of elements + template + fifo_map(InputIterator first, InputIterator last) + : m_keys(), m_compare(&m_keys), m_map(m_compare) + { + for (auto it = first; it != last; ++it) + { + insert(*it); + } + } + + /// constructor for a list of elements + fifo_map(std::initializer_list init) : fifo_map() + { + for (auto x : init) + { + insert(x); + } + } + + + /* + * Element access + */ + + /// access specified element with bounds checking + T& at(const Key& key) + { + return m_map.at(key); + } + + /// access specified element with bounds checking + const T& at(const Key& key) const + { + return m_map.at(key); + } + + /// access specified element + T& operator[](const Key& key) + { + m_compare.add_key(key); + return m_map[key]; + } + + /// access specified element + T& operator[](Key&& key) + { + m_compare.add_key(key); + return m_map[key]; + } + + + /* + * Iterators + */ + + /// returns an iterator to the beginning + iterator begin() noexcept + { + return m_map.begin(); + } + + /// returns an iterator to the end + iterator end() noexcept + { + return m_map.end(); + } + + /// returns an iterator to the beginning + const_iterator begin() const noexcept + { + return m_map.begin(); + } + + /// returns an iterator to the end + const_iterator end() const noexcept + { + return m_map.end(); + } + + /// returns an iterator to the beginning + const_iterator cbegin() const noexcept + { + return m_map.cbegin(); + } + + /// returns an iterator to the end + const_iterator cend() const noexcept + { + return m_map.cend(); + } + + /// returns a reverse iterator to the beginning + reverse_iterator rbegin() noexcept + { + return m_map.rbegin(); + } + + /// returns a reverse iterator to the end + reverse_iterator rend() noexcept + { + return m_map.rend(); + } + + /// returns a reverse iterator to the beginning + const_reverse_iterator rbegin() const noexcept + { + return m_map.rbegin(); + } + + /// returns a reverse iterator to the end + const_reverse_iterator rend() const noexcept + { + return m_map.rend(); + } + + /// returns a reverse iterator to the beginning + const_reverse_iterator crbegin() const noexcept + { + return m_map.crbegin(); + } + + /// returns a reverse iterator to the end + const_reverse_iterator crend() const noexcept + { + return m_map.crend(); + } + + + /* + * Capacity + */ + + /// checks whether the container is empty + bool empty() const noexcept + { + return m_map.empty(); + } + + /// returns the number of elements + size_type size() const noexcept + { + return m_map.size(); + } + + /// returns the maximum possible number of elements + size_type max_size() const noexcept + { + return m_map.max_size(); + } + + + /* + * Modifiers + */ + + /// clears the contents + void clear() noexcept + { + m_map.clear(); + m_keys.clear(); + } + + /// insert value + std::pair insert(const value_type& value) + { + m_compare.add_key(value.first); + return m_map.insert(value); + } + + /// insert value + template + std::pair insert( P&& value ) + { + m_compare.add_key(value.first); + return m_map.insert(value); + } + + /// insert value with hint + iterator insert(const_iterator hint, const value_type& value) + { + m_compare.add_key(value.first); + return m_map.insert(hint, value); + } + + /// insert value with hint + iterator insert(const_iterator hint, value_type&& value) + { + m_compare.add_key(value.first); + return m_map.insert(hint, value); + } + + /// insert value range + template + void insert(InputIt first, InputIt last) + { + for (const_iterator it = first; it != last; ++it) + { + m_compare.add_key(it->first); + } + + m_map.insert(first, last); + } + + /// insert value list + void insert(std::initializer_list ilist) + { + for (auto value : ilist) + { + m_compare.add_key(value.first); + } + + m_map.insert(ilist); + } + + /// constructs element in-place + template + std::pair emplace(Args&& ... args) + { + typename fifo_map::value_type value(std::forward(args)...); + m_compare.add_key(value.first); + return m_map.emplace(std::move(value)); + } + + /// constructs element in-place with hint + template + iterator emplace_hint(const_iterator hint, Args&& ... args) + { + typename fifo_map::value_type value(std::forward(args)...); + m_compare.add_key(value.first); + return m_map.emplace_hint(hint, std::move(value)); + } + + /// remove element at position + iterator erase(const_iterator pos) + { + m_compare.remove_key(pos->first); + return m_map.erase(pos); + } + + /// remove elements in range + iterator erase(const_iterator first, const_iterator last) + { + for (const_iterator it = first; it != last; ++it) + { + m_compare.remove_key(it->first); + } + + return m_map.erase(first, last); + } + + /// remove elements with key + size_type erase(const key_type& key) + { + size_type res = m_map.erase(key); + + if (res > 0) + { + m_compare.remove_key(key); + } + + return res; + } + + /// swaps the contents + void swap(fifo_map& other) + { + std::swap(m_map, other.m_map); + std::swap(m_compare, other.m_compare); + std::swap(m_keys, other.m_keys); + } + + + /* + * Lookup + */ + + /// returns the number of elements matching specific key + size_type count(const Key& key) const + { + return m_map.count(key); + } + + /// finds element with specific key + iterator find(const Key& key) + { + return m_map.find(key); + } + + /// finds element with specific key + const_iterator find(const Key& key) const + { + return m_map.find(key); + } + + /// returns range of elements matching a specific key + std::pair equal_range(const Key& key) + { + return m_map.equal_range(key); + } + + /// returns range of elements matching a specific key + std::pair equal_range(const Key& key) const + { + return m_map.equal_range(key); + } + + /// returns an iterator to the first element not less than the given key + iterator lower_bound(const Key& key) + { + return m_map.lower_bound(key); + } + + /// returns an iterator to the first element not less than the given key + const_iterator lower_bound(const Key& key) const + { + return m_map.lower_bound(key); + } + + /// returns an iterator to the first element greater than the given key + iterator upper_bound(const Key& key) + { + return m_map.upper_bound(key); + } + + /// returns an iterator to the first element greater than the given key + const_iterator upper_bound(const Key& key) const + { + return m_map.upper_bound(key); + } + + + /* + * Observers + */ + + /// returns the function that compares keys + key_compare key_comp() const + { + return m_compare; + } + + + /* + * Non-member functions + */ + + friend bool operator==(const fifo_map& lhs, const fifo_map& rhs) + { + return lhs.m_map == rhs.m_map; + } + + friend bool operator!=(const fifo_map& lhs, const fifo_map& rhs) + { + return lhs.m_map != rhs.m_map; + } + + friend bool operator<(const fifo_map& lhs, const fifo_map& rhs) + { + return lhs.m_map < rhs.m_map; + } + + friend bool operator<=(const fifo_map& lhs, const fifo_map& rhs) + { + return lhs.m_map <= rhs.m_map; + } + + friend bool operator>(const fifo_map& lhs, const fifo_map& rhs) + { + return lhs.m_map > rhs.m_map; + } + + friend bool operator>=(const fifo_map& lhs, const fifo_map& rhs) + { + return lhs.m_map >= rhs.m_map; + } + + private: + /// the keys + std::unordered_map m_keys; + /// the comparison object + Compare m_compare; + /// the internal data structure + internal_map_type m_map; +}; + +} + +// specialization of std::swap +namespace std +{ +template +inline void swap(nlohmann::fifo_map& m1, + nlohmann::fifo_map& m2) +{ + m1.swap(m2); +} +} + +#endif