From 0fe9f23254c98172c71a08ca5a1f75d4e6974811 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sat, 20 Jun 2020 14:11:37 +0200 Subject: [PATCH 01/18] :sparkles: add macros from #2175 --- include/nlohmann/detail/macro_scope.hpp | 41 ++++++++ single_include/nlohmann/json.hpp | 41 ++++++++ test/CMakeLists.txt | 1 + test/src/unit-udt_macro.cpp | 126 ++++++++++++++++++++++++ 4 files changed, 209 insertions(+) create mode 100644 test/src/unit-udt_macro.cpp diff --git a/include/nlohmann/detail/macro_scope.hpp b/include/nlohmann/detail/macro_scope.hpp index 25e6b76e..92bc6370 100644 --- a/include/nlohmann/detail/macro_scope.hpp +++ b/include/nlohmann/detail/macro_scope.hpp @@ -120,3 +120,44 @@ basic_json + +// Macros to simplify conversion from/to types + +#define NLOHMANN_JSON_EXPAND( x ) x +#define NLOHMANN_JSON_GET_MACRO(_1,_2,_3,_4,_5,_6, _7, _8, _9, _10, _11, NAME,...) NAME + +#define NLOHMANN_JSON_PASTE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_GET_MACRO(__VA_ARGS__, NLOHMANN_JSON_PASTE11, \ + NLOHMANN_JSON_PASTE10, NLOHMANN_JSON_PASTE9, NLOHMANN_JSON_PASTE8, NLOHMANN_JSON_PASTE7, \ + NLOHMANN_JSON_PASTE6, NLOHMANN_JSON_PASTE5, NLOHMANN_JSON_PASTE4, NLOHMANN_JSON_PASTE3, \ + NLOHMANN_JSON_PASTE2, NLOHMANN_JSON_PASTE1)(__VA_ARGS__)) +#define NLOHMANN_JSON_PASTE2(func, v1) func(v1) +#define NLOHMANN_JSON_PASTE3(func, v1, v2) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE2(func, v2) +#define NLOHMANN_JSON_PASTE4(func, v1, v2, v3) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE3(func, v2, v3) +#define NLOHMANN_JSON_PASTE5(func, v1, v2, v3, v4) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE4(func, v2, v3, v4) +#define NLOHMANN_JSON_PASTE6(func, v1, v2, v3, v4, v5) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE5(func, v2, v3, v4, v5) +#define NLOHMANN_JSON_PASTE7(func, v1, v2, v3, v4, v5, v6) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE6(func, v2, v3, v4, v5, v6) +#define NLOHMANN_JSON_PASTE8(func, v1, v2, v3, v4, v5, v6, v7) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE7(func, v2, v3, v4, v5, v6, v7) +#define NLOHMANN_JSON_PASTE9(func, v1, v2, v3, v4, v5, v6, v7, v8) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE8(func, v2, v3, v4, v5, v6, v7, v8) +#define NLOHMANN_JSON_PASTE10(func, v1, v2, v3, v4, v5, v6, v7, v8, v9) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE8(func, v2, v3, v4, v5, v6, v7, v8, v9) +#define NLOHMANN_JSON_PASTE11(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE8(func, v2, v3, v4, v5, v6, v7, v8, v9, v10) + +#define NLOHMANN_JSON_TO(v1) j[#v1] = t.v1; +#define NLOHMANN_JSON_FROM(v1) j.at(#v1).get_to(t.v1); + +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_INTRUSIVE +@since version 3.9.0 +*/ +#define NLOHMANN_DEFINE_TYPE_INTRUSIVE(Type, ...) \ + friend void to_json(nlohmann::json& j, const Type& t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + friend void from_json(const nlohmann::json& j, Type& t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE +@since version 3.9.0 +*/ +#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Type, ...) \ + void to_json(nlohmann::json& j, const Type& t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + void from_json(const nlohmann::json& j, Type& t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index cc822a54..0c34d28e 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -2149,6 +2149,47 @@ JSON_HEDLEY_DIAGNOSTIC_POP NumberIntegerType, NumberUnsignedType, NumberFloatType, \ AllocatorType, JSONSerializer, BinaryType> +// Macros to simplify conversion from/to types + +#define NLOHMANN_JSON_EXPAND( x ) x +#define NLOHMANN_JSON_GET_MACRO(_1,_2,_3,_4,_5,_6, _7, _8, _9, _10, _11, NAME,...) NAME + +#define NLOHMANN_JSON_PASTE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_GET_MACRO(__VA_ARGS__, NLOHMANN_JSON_PASTE11, \ + NLOHMANN_JSON_PASTE10, NLOHMANN_JSON_PASTE9, NLOHMANN_JSON_PASTE8, NLOHMANN_JSON_PASTE7, \ + NLOHMANN_JSON_PASTE6, NLOHMANN_JSON_PASTE5, NLOHMANN_JSON_PASTE4, NLOHMANN_JSON_PASTE3, \ + NLOHMANN_JSON_PASTE2, NLOHMANN_JSON_PASTE1)(__VA_ARGS__)) +#define NLOHMANN_JSON_PASTE2(func, v1) func(v1) +#define NLOHMANN_JSON_PASTE3(func, v1, v2) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE2(func, v2) +#define NLOHMANN_JSON_PASTE4(func, v1, v2, v3) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE3(func, v2, v3) +#define NLOHMANN_JSON_PASTE5(func, v1, v2, v3, v4) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE4(func, v2, v3, v4) +#define NLOHMANN_JSON_PASTE6(func, v1, v2, v3, v4, v5) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE5(func, v2, v3, v4, v5) +#define NLOHMANN_JSON_PASTE7(func, v1, v2, v3, v4, v5, v6) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE6(func, v2, v3, v4, v5, v6) +#define NLOHMANN_JSON_PASTE8(func, v1, v2, v3, v4, v5, v6, v7) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE7(func, v2, v3, v4, v5, v6, v7) +#define NLOHMANN_JSON_PASTE9(func, v1, v2, v3, v4, v5, v6, v7, v8) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE8(func, v2, v3, v4, v5, v6, v7, v8) +#define NLOHMANN_JSON_PASTE10(func, v1, v2, v3, v4, v5, v6, v7, v8, v9) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE8(func, v2, v3, v4, v5, v6, v7, v8, v9) +#define NLOHMANN_JSON_PASTE11(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE8(func, v2, v3, v4, v5, v6, v7, v8, v9, v10) + +#define NLOHMANN_JSON_TO(v1) j[#v1] = t.v1; +#define NLOHMANN_JSON_FROM(v1) j.at(#v1).get_to(t.v1); + +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_INTRUSIVE +@since version 3.9.0 +*/ +#define NLOHMANN_DEFINE_TYPE_INTRUSIVE(Type, ...) \ + friend void to_json(nlohmann::json& j, const Type& t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + friend void from_json(const nlohmann::json& j, Type& t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE +@since version 3.9.0 +*/ +#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Type, ...) \ + void to_json(nlohmann::json& j, const Type& t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + void from_json(const nlohmann::json& j, Type& t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } + namespace nlohmann { diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index fdf5ac5b..8434f78d 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -132,6 +132,7 @@ set(files src/unit-to_chars.cpp src/unit-ubjson.cpp src/unit-udt.cpp + src/unit-udt_macro.cpp src/unit-unicode.cpp src/unit-user_defined_input.cpp src/unit-wstring.cpp) diff --git a/test/src/unit-udt_macro.cpp b/test/src/unit-udt_macro.cpp new file mode 100644 index 00000000..ab2d3245 --- /dev/null +++ b/test/src/unit-udt_macro.cpp @@ -0,0 +1,126 @@ +/* + __ _____ _____ _____ + __| | __| | | | JSON for Modern C++ (test suite) +| | |__ | | | | | | version 3.8.0 +|_____|_____|_____|_|___| https://github.com/nlohmann/json + +Licensed under the MIT License . +SPDX-License-Identifier: MIT +Copyright (c) 2013-2019 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. +*/ + +#include "doctest_compatibility.h" + +#include +using nlohmann::json; + +#include + +namespace persons +{ +class person_with_private_data +{ + private: + std::string name; + int age = 0; + + public: + bool operator==(const person_with_private_data& rhs) const + { + return std::tie(name, age) == std::tie(rhs.name, rhs.age); + } + + person_with_private_data() = default; + person_with_private_data(std::string name, int age) + : name(std::move(name)) + , age(age) + {} + + NLOHMANN_DEFINE_TYPE_INTRUSIVE(person_with_private_data, age, name); +}; + +class person_without_private_data_1 +{ + public: + std::string name; + int age = 0; + + bool operator==(const person_without_private_data_1& rhs) const + { + return std::tie(name, age) == std::tie(rhs.name, rhs.age); + } + + person_without_private_data_1() = default; + person_without_private_data_1(std::string name, int age) + : name(std::move(name)) + , age(age) + {} + + NLOHMANN_DEFINE_TYPE_INTRUSIVE(person_without_private_data_1, age, name); +}; + +class person_without_private_data_2 +{ + public: + std::string name; + int age = 0; + + bool operator==(const person_without_private_data_2& rhs) const + { + return std::tie(name, age) == std::tie(rhs.name, rhs.age); + } + + person_without_private_data_2() = default; + person_without_private_data_2(std::string name, int age) + : name(std::move(name)) + , age(age) + {} +}; + +NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(person_without_private_data_2, age, name); +} // namespace persons + +TEST_CASE_TEMPLATE("Serialization/deserialization via NLOHMANN_DEFINE_TYPE_INTRUSIVE", T, + persons::person_with_private_data, + persons::person_without_private_data_1, + persons::person_without_private_data_2) +{ + SECTION("person") + { + // serialization + T p1("Erik", 1); + CHECK(json(p1).dump() == "{\"age\":1,\"name\":\"Erik\"}"); + + // deserialization + T p2 = json(p1); + CHECK(p2 == p1); + + // roundtrip + CHECK(T(json(p1)) == p1); + CHECK(json(T(json(p1))) == json(p1)); + + // check exception in case of missing field + json j = json(p1); + j.erase("age"); + T p3; + CHECK_THROWS_WITH_AS(p3 = json(j), "[json.exception.out_of_range.403] key 'age' not found", json::out_of_range); + } +} From fa9f4040dffe11792d473552f7786e8bc60f290c Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sat, 27 Jun 2020 13:07:02 +0200 Subject: [PATCH 02/18] :fire: remove unused typedefs #2221 --- include/nlohmann/detail/json_pointer.hpp | 6 ------ single_include/nlohmann/json.hpp | 6 ------ 2 files changed, 12 deletions(-) diff --git a/include/nlohmann/detail/json_pointer.hpp b/include/nlohmann/detail/json_pointer.hpp index 56280292..ea14861b 100644 --- a/include/nlohmann/detail/json_pointer.hpp +++ b/include/nlohmann/detail/json_pointer.hpp @@ -398,7 +398,6 @@ class json_pointer */ BasicJsonType& get_and_create(BasicJsonType& j) const { - using size_type = typename BasicJsonType::size_type; auto result = &j; // in case no reference tokens exist, return a reference to the JSON value @@ -471,7 +470,6 @@ class json_pointer */ BasicJsonType& get_unchecked(BasicJsonType* ptr) const { - using size_type = typename BasicJsonType::size_type; for (const auto& reference_token : reference_tokens) { // convert null values to arrays or objects before continuing @@ -531,7 +529,6 @@ class json_pointer */ BasicJsonType& get_checked(BasicJsonType* ptr) const { - using size_type = typename BasicJsonType::size_type; for (const auto& reference_token : reference_tokens) { switch (ptr->type()) @@ -581,7 +578,6 @@ class json_pointer */ const BasicJsonType& get_unchecked(const BasicJsonType* ptr) const { - using size_type = typename BasicJsonType::size_type; for (const auto& reference_token : reference_tokens) { switch (ptr->type()) @@ -624,7 +620,6 @@ class json_pointer */ const BasicJsonType& get_checked(const BasicJsonType* ptr) const { - using size_type = typename BasicJsonType::size_type; for (const auto& reference_token : reference_tokens) { switch (ptr->type()) @@ -665,7 +660,6 @@ class json_pointer */ bool contains(const BasicJsonType* ptr) const { - using size_type = typename BasicJsonType::size_type; for (const auto& reference_token : reference_tokens) { switch (ptr->type()) diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 770418f4..3a4fc022 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -11529,7 +11529,6 @@ class json_pointer */ BasicJsonType& get_and_create(BasicJsonType& j) const { - using size_type = typename BasicJsonType::size_type; auto result = &j; // in case no reference tokens exist, return a reference to the JSON value @@ -11602,7 +11601,6 @@ class json_pointer */ BasicJsonType& get_unchecked(BasicJsonType* ptr) const { - using size_type = typename BasicJsonType::size_type; for (const auto& reference_token : reference_tokens) { // convert null values to arrays or objects before continuing @@ -11662,7 +11660,6 @@ class json_pointer */ BasicJsonType& get_checked(BasicJsonType* ptr) const { - using size_type = typename BasicJsonType::size_type; for (const auto& reference_token : reference_tokens) { switch (ptr->type()) @@ -11712,7 +11709,6 @@ class json_pointer */ const BasicJsonType& get_unchecked(const BasicJsonType* ptr) const { - using size_type = typename BasicJsonType::size_type; for (const auto& reference_token : reference_tokens) { switch (ptr->type()) @@ -11755,7 +11751,6 @@ class json_pointer */ const BasicJsonType& get_checked(const BasicJsonType* ptr) const { - using size_type = typename BasicJsonType::size_type; for (const auto& reference_token : reference_tokens) { switch (ptr->type()) @@ -11796,7 +11791,6 @@ class json_pointer */ bool contains(const BasicJsonType* ptr) const { - using size_type = typename BasicJsonType::size_type; for (const auto& reference_token : reference_tokens) { switch (ptr->type()) From 470f7c0c68a967e853781cde039486ab93866431 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Mon, 29 Jun 2020 13:43:06 +0200 Subject: [PATCH 03/18] :memo: add documentation --- README.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/README.md b/README.md index d7492da3..1052cc0c 100644 --- a/README.md +++ b/README.md @@ -869,6 +869,42 @@ Some important things: * In function `from_json`, use function [`at()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a93403e803947b86f4da2d1fb3345cf2c.html#a93403e803947b86f4da2d1fb3345cf2c) to access the object values rather than `operator[]`. In case a key does not exist, `at` throws an exception that you can handle, whereas `operator[]` exhibits undefined behavior. * You do not need to add serializers or deserializers for STL types like `std::vector`: the library already implements these. +#### Simplify your life with macros + +If you just want to serialize/deserialize some structs, the `to_json`/`from_json` functions can be a lot of boilerplate. + +There are two macros to make your life easier as long as you (1) want to use a JSON object as serialization and (2) want to use the member variable names as object keys in that object: + +- `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(name, member1, member2, ...)` is to be defined inside of the namespace of the class/struct to create code for. +- `NLOHMANN_DEFINE_TYPE_INTRUSIVE(name, member1, member2, ...)` is to be defined inside of the class/struct to create code for. This macro can also access private members. + +In both macros, the first parameter is the name of the class/struct, and all remaining parameters name the members. + +##### Examples + +The `to_json`/`from_json` functions for the `person` struct above can be created with: + +```cpp +namespace ns { + NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(person, name, address, age); +} +``` + +Here is an example with private members, where `NLOHMANN_DEFINE_TYPE_INTRUSIVE` is needed: + +```cpp +namespace ns { + class address { + private: + std::string street; + int housenumber; + int postcode; + + public: + NLOHMANN_DEFINE_TYPE_INTRUSIVE(address, street, housenumber, postcode); + }; +} +``` #### How do I convert third-party types? From ad6eadeb70b6ba20cec985dea8da829fda2fbdd9 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Tue, 30 Jun 2020 13:59:43 +0200 Subject: [PATCH 04/18] :memo: refine documentation of error_handler parameter --- include/nlohmann/json.hpp | 3 ++- single_include/nlohmann/json.hpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index ace649b6..998aa720 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -2238,7 +2238,8 @@ class basic_json @param[in] error_handler how to react on decoding errors; there are three possible values: `strict` (throws and exception in case a decoding error occurs; default), `replace` (replace invalid UTF-8 sequences with U+FFFD), - and `ignore` (ignore invalid UTF-8 sequences during serialization). + and `ignore` (ignore invalid UTF-8 sequences during serialization; all + bytes are copied to the output unchanged). @return string containing the serialization of the JSON value diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 7ab24c84..426ee815 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -18168,7 +18168,8 @@ class basic_json @param[in] error_handler how to react on decoding errors; there are three possible values: `strict` (throws and exception in case a decoding error occurs; default), `replace` (replace invalid UTF-8 sequences with U+FFFD), - and `ignore` (ignore invalid UTF-8 sequences during serialization). + and `ignore` (ignore invalid UTF-8 sequences during serialization; all + bytes are copied to the output unchanged). @return string containing the serialization of the JSON value From c7e079cc98a6c5534e8d4a209dd0984e569d0625 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Tue, 30 Jun 2020 14:26:52 +0200 Subject: [PATCH 05/18] :ambulance: add specialization of get_to #2175 --- include/nlohmann/json.hpp | 12 ++++++++++++ single_include/nlohmann/json.hpp | 12 ++++++++++++ test/src/unit-udt_macro.cpp | 28 +++++++++++++++++----------- 3 files changed, 41 insertions(+), 11 deletions(-) diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index ace649b6..00b7ce55 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -3019,6 +3019,18 @@ class basic_json return v; } + // specialization to allow to call get_to with a basic_json value + // see https://github.com/nlohmann/json/issues/2175 + template::value, + int> = 0> + ValueType & get_to(ValueType& v) const + { + v = *this; + return v; + } + template < typename T, std::size_t N, typename Array = T (&)[N], diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 7ab24c84..9cba3069 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -18949,6 +18949,18 @@ class basic_json return v; } + // specialization to allow to call get_to with a basic_json value + // see https://github.com/nlohmann/json/issues/2175 + template::value, + int> = 0> + ValueType & get_to(ValueType& v) const + { + v = *this; + return v; + } + template < typename T, std::size_t N, typename Array = T (&)[N], diff --git a/test/src/unit-udt_macro.cpp b/test/src/unit-udt_macro.cpp index ab2d3245..a45b2c50 100644 --- a/test/src/unit-udt_macro.cpp +++ b/test/src/unit-udt_macro.cpp @@ -41,20 +41,22 @@ class person_with_private_data private: std::string name; int age = 0; + json metadata; public: bool operator==(const person_with_private_data& rhs) const { - return std::tie(name, age) == std::tie(rhs.name, rhs.age); + return std::tie(name, age, metadata) == std::tie(rhs.name, rhs.age, rhs.metadata); } person_with_private_data() = default; - person_with_private_data(std::string name, int age) + person_with_private_data(std::string name, int age, json metadata) : name(std::move(name)) , age(age) + , metadata(std::move(metadata)) {} - NLOHMANN_DEFINE_TYPE_INTRUSIVE(person_with_private_data, age, name); + NLOHMANN_DEFINE_TYPE_INTRUSIVE(person_with_private_data, age, name, metadata); }; class person_without_private_data_1 @@ -62,19 +64,21 @@ class person_without_private_data_1 public: std::string name; int age = 0; + json metadata; bool operator==(const person_without_private_data_1& rhs) const { - return std::tie(name, age) == std::tie(rhs.name, rhs.age); + return std::tie(name, age, metadata) == std::tie(rhs.name, rhs.age, rhs.metadata); } person_without_private_data_1() = default; - person_without_private_data_1(std::string name, int age) + person_without_private_data_1(std::string name, int age, json metadata) : name(std::move(name)) , age(age) + , metadata(std::move(metadata)) {} - NLOHMANN_DEFINE_TYPE_INTRUSIVE(person_without_private_data_1, age, name); + NLOHMANN_DEFINE_TYPE_INTRUSIVE(person_without_private_data_1, age, name, metadata); }; class person_without_private_data_2 @@ -82,20 +86,22 @@ class person_without_private_data_2 public: std::string name; int age = 0; + json metadata; bool operator==(const person_without_private_data_2& rhs) const { - return std::tie(name, age) == std::tie(rhs.name, rhs.age); + return std::tie(name, age, metadata) == std::tie(rhs.name, rhs.age, rhs.metadata); } person_without_private_data_2() = default; - person_without_private_data_2(std::string name, int age) + person_without_private_data_2(std::string name, int age, json metadata) : name(std::move(name)) , age(age) + , metadata(std::move(metadata)) {} }; -NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(person_without_private_data_2, age, name); +NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(person_without_private_data_2, age, name, metadata); } // namespace persons TEST_CASE_TEMPLATE("Serialization/deserialization via NLOHMANN_DEFINE_TYPE_INTRUSIVE", T, @@ -106,8 +112,8 @@ TEST_CASE_TEMPLATE("Serialization/deserialization via NLOHMANN_DEFINE_TYPE_INTRU SECTION("person") { // serialization - T p1("Erik", 1); - CHECK(json(p1).dump() == "{\"age\":1,\"name\":\"Erik\"}"); + T p1("Erik", 1, {{"haircuts", 2}}); + CHECK(json(p1).dump() == "{\"age\":1,\"metadata\":{\"haircuts\":2},\"name\":\"Erik\"}"); // deserialization T p2 = json(p1); From f59f4a2b61161f8aab0d7b499fbb9b7a94b66188 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Tue, 30 Jun 2020 19:55:40 +0200 Subject: [PATCH 06/18] :green_heart: fix build --- test/src/unit-udt_macro.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/test/src/unit-udt_macro.cpp b/test/src/unit-udt_macro.cpp index a45b2c50..4535ae5b 100644 --- a/test/src/unit-udt_macro.cpp +++ b/test/src/unit-udt_macro.cpp @@ -32,8 +32,6 @@ SOFTWARE. #include using nlohmann::json; -#include - namespace persons { class person_with_private_data @@ -46,7 +44,7 @@ class person_with_private_data public: bool operator==(const person_with_private_data& rhs) const { - return std::tie(name, age, metadata) == std::tie(rhs.name, rhs.age, rhs.metadata); + return name == rhs.name && age == rhs.age && metadata == rhs.metadata; } person_with_private_data() = default; @@ -68,7 +66,7 @@ class person_without_private_data_1 bool operator==(const person_without_private_data_1& rhs) const { - return std::tie(name, age, metadata) == std::tie(rhs.name, rhs.age, rhs.metadata); + return name == rhs.name && age == rhs.age && metadata == rhs.metadata; } person_without_private_data_1() = default; @@ -90,7 +88,7 @@ class person_without_private_data_2 bool operator==(const person_without_private_data_2& rhs) const { - return std::tie(name, age, metadata) == std::tie(rhs.name, rhs.age, rhs.metadata); + return name == rhs.name && age == rhs.age && metadata == rhs.metadata; } person_without_private_data_2() = default; From 98b1c6d302d6b5eb4be0a3909e1dc09f920d8154 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Mon, 6 Jul 2020 12:22:31 +0200 Subject: [PATCH 07/18] :triangular_flag_on_post: use JSON_ASSERT(x) instead of assert(x) --- README.md | 2 +- .../nlohmann/detail/conversions/to_chars.hpp | 81 +++--- .../nlohmann/detail/input/binary_reader.hpp | 9 +- .../nlohmann/detail/input/input_adapters.hpp | 9 +- include/nlohmann/detail/input/json_sax.hpp | 29 +- include/nlohmann/detail/input/lexer.hpp | 24 +- include/nlohmann/detail/input/parser.hpp | 5 +- .../nlohmann/detail/iterators/iter_impl.hpp | 34 +-- .../detail/iterators/iteration_proxy.hpp | 2 +- include/nlohmann/detail/json_pointer.hpp | 5 +- include/nlohmann/detail/macro_scope.hpp | 6 + include/nlohmann/detail/macro_unscope.hpp | 1 + .../nlohmann/detail/output/binary_writer.hpp | 12 +- include/nlohmann/detail/output/serializer.hpp | 33 +-- include/nlohmann/json.hpp | 25 +- single_include/nlohmann/json.hpp | 275 +++++++++--------- 16 files changed, 275 insertions(+), 277 deletions(-) diff --git a/README.md b/README.md index 6d21e2d8..7a7a46ad 100644 --- a/README.md +++ b/README.md @@ -1572,7 +1572,7 @@ Here is a related issue [#1924](https://github.com/nlohmann/json/issues/1924). ### Further notes -- The code contains numerous debug **assertions** which can be switched off by defining the preprocessor macro `NDEBUG`, see the [documentation of `assert`](https://en.cppreference.com/w/cpp/error/assert). In particular, note [`operator[]`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a233b02b0839ef798942dd46157cc0fe6.html#a233b02b0839ef798942dd46157cc0fe6) implements **unchecked access** for const objects: If the given key is not present, the behavior is undefined (think of a dereferenced null pointer) and yields an [assertion failure](https://github.com/nlohmann/json/issues/289) if assertions are switched on. If you are not sure whether an element in an object exists, use checked access with the [`at()` function](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a73ae333487310e3302135189ce8ff5d8.html#a73ae333487310e3302135189ce8ff5d8). +- The code contains numerous debug **assertions** which can be switched off by defining the preprocessor macro `NDEBUG`, see the [documentation of `assert`](https://en.cppreference.com/w/cpp/error/assert). In particular, note [`operator[]`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a233b02b0839ef798942dd46157cc0fe6.html#a233b02b0839ef798942dd46157cc0fe6) implements **unchecked access** for const objects: If the given key is not present, the behavior is undefined (think of a dereferenced null pointer) and yields an [assertion failure](https://github.com/nlohmann/json/issues/289) if assertions are switched on. If you are not sure whether an element in an object exists, use checked access with the [`at()` function](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a73ae333487310e3302135189ce8ff5d8.html#a73ae333487310e3302135189ce8ff5d8). Furthermore, you can define `JSON_ASSERT(x)` to replace calls to `assert(x)`. - As the exact type of a number is not defined in the [JSON specification](https://tools.ietf.org/html/rfc8259.html), this library tries to choose the best fitting C++ number type automatically. As a result, the type `double` may be used to store numbers which may yield [**floating-point exceptions**](https://github.com/nlohmann/json/issues/181) in certain rare situations if floating-point exceptions have been unmasked in the calling code. These exceptions are not caused by the library and need to be fixed in the calling code, such as by re-masking the exceptions prior to calling library functions. - The code can be compiled without C++ **runtime type identification** features; that is, you can use the `-fno-rtti` compiler flag. - **Exceptions** are used widely within the library. They can, however, be switched off with either using the compiler flag `-fno-exceptions` or by defining the symbol `JSON_NOEXCEPTION`. In this case, exceptions are replaced by `abort()` calls. You can further control this behavior by defining `JSON_THROW_USER´` (overriding `throw`), `JSON_TRY_USER` (overriding `try`), and `JSON_CATCH_USER` (overriding `catch`). Note that `JSON_THROW_USER` should leave the current scope (e.g., by throwing or aborting), as continuing after it may yield undefined behavior. diff --git a/include/nlohmann/detail/conversions/to_chars.hpp b/include/nlohmann/detail/conversions/to_chars.hpp index 5851fd0a..0907e765 100644 --- a/include/nlohmann/detail/conversions/to_chars.hpp +++ b/include/nlohmann/detail/conversions/to_chars.hpp @@ -1,7 +1,6 @@ #pragma once #include // array -#include // assert #include // signbit, isfinite #include // intN_t, uintN_t #include // memcpy, memmove @@ -63,8 +62,8 @@ struct diyfp // f * 2^e */ static diyfp sub(const diyfp& x, const diyfp& y) noexcept { - assert(x.e == y.e); - assert(x.f >= y.f); + JSON_ASSERT(x.e == y.e); + JSON_ASSERT(x.f >= y.f); return {x.f - y.f, x.e}; } @@ -140,7 +139,7 @@ struct diyfp // f * 2^e */ static diyfp normalize(diyfp x) noexcept { - assert(x.f != 0); + JSON_ASSERT(x.f != 0); while ((x.f >> 63u) == 0) { @@ -159,8 +158,8 @@ struct diyfp // f * 2^e { const int delta = x.e - target_exponent; - assert(delta >= 0); - assert(((x.f << delta) >> delta) == x.f); + JSON_ASSERT(delta >= 0); + JSON_ASSERT(((x.f << delta) >> delta) == x.f); return {x.f << delta, target_exponent}; } @@ -182,8 +181,8 @@ boundaries. template boundaries compute_boundaries(FloatType value) { - assert(std::isfinite(value)); - assert(value > 0); + JSON_ASSERT(std::isfinite(value)); + JSON_ASSERT(value > 0); // Convert the IEEE representation into a diyfp. // @@ -463,18 +462,18 @@ inline cached_power get_cached_power_for_binary_exponent(int e) // k = ceil((kAlpha - e - 1) * 0.30102999566398114) // for |e| <= 1500, but doesn't require floating-point operations. // NB: log_10(2) ~= 78913 / 2^18 - assert(e >= -1500); - assert(e <= 1500); + JSON_ASSERT(e >= -1500); + JSON_ASSERT(e <= 1500); const int f = kAlpha - e - 1; const int k = (f * 78913) / (1 << 18) + static_cast(f > 0); const int index = (-kCachedPowersMinDecExp + k + (kCachedPowersDecStep - 1)) / kCachedPowersDecStep; - assert(index >= 0); - assert(static_cast(index) < kCachedPowers.size()); + JSON_ASSERT(index >= 0); + JSON_ASSERT(static_cast(index) < kCachedPowers.size()); const cached_power cached = kCachedPowers[static_cast(index)]; - assert(kAlpha <= cached.e + e + 64); - assert(kGamma >= cached.e + e + 64); + JSON_ASSERT(kAlpha <= cached.e + e + 64); + JSON_ASSERT(kGamma >= cached.e + e + 64); return cached; } @@ -542,10 +541,10 @@ inline int find_largest_pow10(const std::uint32_t n, std::uint32_t& pow10) inline void grisu2_round(char* buf, int len, std::uint64_t dist, std::uint64_t delta, std::uint64_t rest, std::uint64_t ten_k) { - assert(len >= 1); - assert(dist <= delta); - assert(rest <= delta); - assert(ten_k > 0); + JSON_ASSERT(len >= 1); + JSON_ASSERT(dist <= delta); + JSON_ASSERT(rest <= delta); + JSON_ASSERT(ten_k > 0); // <--------------------------- delta ----> // <---- dist ---------> @@ -570,7 +569,7 @@ inline void grisu2_round(char* buf, int len, std::uint64_t dist, std::uint64_t d and delta - rest >= ten_k and (rest + ten_k < dist or dist - rest > rest + ten_k - dist)) { - assert(buf[len - 1] != '0'); + JSON_ASSERT(buf[len - 1] != '0'); buf[len - 1]--; rest += ten_k; } @@ -598,8 +597,8 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent, // Grisu2 generates the digits of M+ from left to right and stops as soon as // V is in [M-,M+]. - assert(M_plus.e >= kAlpha); - assert(M_plus.e <= kGamma); + JSON_ASSERT(M_plus.e >= kAlpha); + JSON_ASSERT(M_plus.e <= kGamma); std::uint64_t delta = diyfp::sub(M_plus, M_minus).f; // (significand of (M+ - M-), implicit exponent is e) std::uint64_t dist = diyfp::sub(M_plus, w ).f; // (significand of (M+ - w ), implicit exponent is e) @@ -620,7 +619,7 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent, // // Generate the digits of the integral part p1 = d[n-1]...d[1]d[0] - assert(p1 > 0); + JSON_ASSERT(p1 > 0); std::uint32_t pow10; const int k = find_largest_pow10(p1, pow10); @@ -656,7 +655,7 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent, // M+ = buffer * 10^n + (d * 10^(n-1) + r) + p2 * 2^e // = (buffer * 10 + d) * 10^(n-1) + (r + p2 * 2^e) // - assert(d <= 9); + JSON_ASSERT(d <= 9); buffer[length++] = static_cast('0' + d); // buffer := buffer * 10 + d // // M+ = buffer * 10^(n-1) + (r + p2 * 2^e) @@ -743,7 +742,7 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent, // // and stop as soon as 10^-m * r * 2^e <= delta * 2^e - assert(p2 > delta); + JSON_ASSERT(p2 > delta); int m = 0; for (;;) @@ -754,7 +753,7 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent, // = buffer * 10^-m + 10^-m * (1/10 * (10 * p2) ) * 2^e // = buffer * 10^-m + 10^-m * (1/10 * ((10*p2 div 2^-e) * 2^-e + (10*p2 mod 2^-e)) * 2^e // - assert(p2 <= (std::numeric_limits::max)() / 10); + JSON_ASSERT(p2 <= (std::numeric_limits::max)() / 10); p2 *= 10; const std::uint64_t d = p2 >> -one.e; // d = (10 * p2) div 2^-e const std::uint64_t r = p2 & (one.f - 1); // r = (10 * p2) mod 2^-e @@ -763,7 +762,7 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent, // = buffer * 10^-m + 10^-m * (1/10 * (d + r * 2^e)) // = (buffer * 10 + d) * 10^(-m-1) + 10^(-m-1) * r * 2^e // - assert(d <= 9); + JSON_ASSERT(d <= 9); buffer[length++] = static_cast('0' + d); // buffer := buffer * 10 + d // // M+ = buffer * 10^(-m-1) + 10^(-m-1) * r * 2^e @@ -824,8 +823,8 @@ JSON_HEDLEY_NON_NULL(1) inline void grisu2(char* buf, int& len, int& decimal_exponent, diyfp m_minus, diyfp v, diyfp m_plus) { - assert(m_plus.e == m_minus.e); - assert(m_plus.e == v.e); + JSON_ASSERT(m_plus.e == m_minus.e); + JSON_ASSERT(m_plus.e == v.e); // --------(-----------------------+-----------------------)-------- (A) // m- v m+ @@ -886,8 +885,8 @@ void grisu2(char* buf, int& len, int& decimal_exponent, FloatType value) static_assert(diyfp::kPrecision >= std::numeric_limits::digits + 3, "internal error: not enough precision"); - assert(std::isfinite(value)); - assert(value > 0); + JSON_ASSERT(std::isfinite(value)); + JSON_ASSERT(value > 0); // If the neighbors (and boundaries) of 'value' are always computed for double-precision // numbers, all float's can be recovered using strtod (and strtof). However, the resulting @@ -923,8 +922,8 @@ JSON_HEDLEY_NON_NULL(1) JSON_HEDLEY_RETURNS_NON_NULL inline char* append_exponent(char* buf, int e) { - assert(e > -1000); - assert(e < 1000); + JSON_ASSERT(e > -1000); + JSON_ASSERT(e < 1000); if (e < 0) { @@ -976,8 +975,8 @@ JSON_HEDLEY_RETURNS_NON_NULL inline char* format_buffer(char* buf, int len, int decimal_exponent, int min_exp, int max_exp) { - assert(min_exp < 0); - assert(max_exp > 0); + JSON_ASSERT(min_exp < 0); + JSON_ASSERT(max_exp > 0); const int k = len; const int n = len + decimal_exponent; @@ -1003,7 +1002,7 @@ inline char* format_buffer(char* buf, int len, int decimal_exponent, // dig.its // len <= max_digits10 + 1 - assert(k > n); + JSON_ASSERT(k > n); std::memmove(buf + (static_cast(n) + 1), buf + n, static_cast(k) - static_cast(n)); buf[n] = '.'; @@ -1061,7 +1060,7 @@ JSON_HEDLEY_RETURNS_NON_NULL char* to_chars(char* first, const char* last, FloatType value) { static_cast(last); // maybe unused - fix warning - assert(std::isfinite(value)); + JSON_ASSERT(std::isfinite(value)); // Use signbit(value) instead of (value < 0) since signbit works for -0. if (std::signbit(value)) @@ -1079,7 +1078,7 @@ char* to_chars(char* first, const char* last, FloatType value) return first; } - assert(last - first >= std::numeric_limits::max_digits10); + JSON_ASSERT(last - first >= std::numeric_limits::max_digits10); // Compute v = buffer * 10^decimal_exponent. // The decimal digits are stored in the buffer, which needs to be interpreted @@ -1089,16 +1088,16 @@ char* to_chars(char* first, const char* last, FloatType value) int decimal_exponent = 0; dtoa_impl::grisu2(first, len, decimal_exponent, value); - assert(len <= std::numeric_limits::max_digits10); + JSON_ASSERT(len <= std::numeric_limits::max_digits10); // Format the buffer like printf("%.*g", prec, value) constexpr int kMinExp = -4; // Use digits10 here to increase compatibility with version 2. constexpr int kMaxExp = std::numeric_limits::digits10; - assert(last - first >= kMaxExp + 2); - assert(last - first >= 2 + (-kMinExp - 1) + std::numeric_limits::max_digits10); - assert(last - first >= std::numeric_limits::max_digits10 + 6); + JSON_ASSERT(last - first >= kMaxExp + 2); + JSON_ASSERT(last - first >= 2 + (-kMinExp - 1) + std::numeric_limits::max_digits10); + JSON_ASSERT(last - first >= std::numeric_limits::max_digits10 + 6); return dtoa_impl::format_buffer(first, len, decimal_exponent, kMinExp, kMaxExp); } diff --git a/include/nlohmann/detail/input/binary_reader.hpp b/include/nlohmann/detail/input/binary_reader.hpp index a27a1538..e075d527 100644 --- a/include/nlohmann/detail/input/binary_reader.hpp +++ b/include/nlohmann/detail/input/binary_reader.hpp @@ -2,7 +2,6 @@ #include // generate_n #include // array -#include // assert #include // ldexp #include // size_t #include // uint8_t, uint16_t, uint32_t, uint64_t @@ -109,7 +108,7 @@ class binary_reader break; default: // LCOV_EXCL_LINE - assert(false); // LCOV_EXCL_LINE + JSON_ASSERT(false); // LCOV_EXCL_LINE } // strict mode: next byte must be EOF @@ -717,8 +716,8 @@ class binary_reader { const int exp = (half >> 10u) & 0x1Fu; const unsigned int mant = half & 0x3FFu; - assert(0 <= exp and exp <= 32); - assert(mant <= 1024); + JSON_ASSERT(0 <= exp and exp <= 32); + JSON_ASSERT(mant <= 1024); switch (exp) { case 0: @@ -2295,7 +2294,7 @@ class binary_reader break; default: // LCOV_EXCL_LINE - assert(false); // LCOV_EXCL_LINE + JSON_ASSERT(false); // LCOV_EXCL_LINE } return error_msg + " " + context + ": " + detail; diff --git a/include/nlohmann/detail/input/input_adapters.hpp b/include/nlohmann/detail/input/input_adapters.hpp index 47ea4a5b..2efccb1a 100644 --- a/include/nlohmann/detail/input/input_adapters.hpp +++ b/include/nlohmann/detail/input/input_adapters.hpp @@ -1,7 +1,6 @@ #pragma once #include // array -#include // assert #include // size_t #include //FILE * #include // strlen @@ -297,13 +296,13 @@ class wide_string_input_adapter { fill_buffer(); - assert(utf8_bytes_filled > 0); - assert(utf8_bytes_index == 0); + JSON_ASSERT(utf8_bytes_filled > 0); + JSON_ASSERT(utf8_bytes_index == 0); } // use buffer - assert(utf8_bytes_filled > 0); - assert(utf8_bytes_index < utf8_bytes_filled); + JSON_ASSERT(utf8_bytes_filled > 0); + JSON_ASSERT(utf8_bytes_index < utf8_bytes_filled); return utf8_bytes[utf8_bytes_index++]; } diff --git a/include/nlohmann/detail/input/json_sax.hpp b/include/nlohmann/detail/input/json_sax.hpp index c7c1db81..18d82822 100644 --- a/include/nlohmann/detail/input/json_sax.hpp +++ b/include/nlohmann/detail/input/json_sax.hpp @@ -1,6 +1,5 @@ #pragma once -#include // assert #include #include // string #include // move @@ -280,7 +279,7 @@ class json_sax_dom_parser case 5: JSON_THROW(*dynamic_cast(&ex)); default: - assert(false); + JSON_ASSERT(false); // LCOV_EXCL_STOP } } @@ -309,7 +308,7 @@ class json_sax_dom_parser return &root; } - assert(ref_stack.back()->is_array() or ref_stack.back()->is_object()); + JSON_ASSERT(ref_stack.back()->is_array() or ref_stack.back()->is_object()); if (ref_stack.back()->is_array()) { @@ -317,8 +316,8 @@ class json_sax_dom_parser return &(ref_stack.back()->m_value.array->back()); } - assert(ref_stack.back()->is_object()); - assert(object_element); + JSON_ASSERT(ref_stack.back()->is_object()); + JSON_ASSERT(object_element); *object_element = BasicJsonType(std::forward(v)); return object_element; } @@ -447,8 +446,8 @@ class json_sax_dom_callback_parser *ref_stack.back() = discarded; } - assert(not ref_stack.empty()); - assert(not keep_stack.empty()); + JSON_ASSERT(not ref_stack.empty()); + JSON_ASSERT(not keep_stack.empty()); ref_stack.pop_back(); keep_stack.pop_back(); @@ -499,8 +498,8 @@ class json_sax_dom_callback_parser } } - assert(not ref_stack.empty()); - assert(not keep_stack.empty()); + JSON_ASSERT(not ref_stack.empty()); + JSON_ASSERT(not keep_stack.empty()); ref_stack.pop_back(); keep_stack.pop_back(); @@ -534,7 +533,7 @@ class json_sax_dom_callback_parser case 5: JSON_THROW(*dynamic_cast(&ex)); default: - assert(false); + JSON_ASSERT(false); // LCOV_EXCL_STOP } } @@ -565,7 +564,7 @@ class json_sax_dom_callback_parser template std::pair handle_value(Value&& v, const bool skip_callback = false) { - assert(not keep_stack.empty()); + JSON_ASSERT(not keep_stack.empty()); // do not handle this value if we know it would be added to a discarded // container @@ -600,7 +599,7 @@ class json_sax_dom_callback_parser } // we now only expect arrays and objects - assert(ref_stack.back()->is_array() or ref_stack.back()->is_object()); + JSON_ASSERT(ref_stack.back()->is_array() or ref_stack.back()->is_object()); // array if (ref_stack.back()->is_array()) @@ -610,9 +609,9 @@ class json_sax_dom_callback_parser } // object - assert(ref_stack.back()->is_object()); + JSON_ASSERT(ref_stack.back()->is_object()); // check if we should store an element for the current key - assert(not key_keep_stack.empty()); + JSON_ASSERT(not key_keep_stack.empty()); const bool store_element = key_keep_stack.back(); key_keep_stack.pop_back(); @@ -621,7 +620,7 @@ class json_sax_dom_callback_parser return {false, nullptr}; } - assert(object_element); + JSON_ASSERT(object_element); *object_element = std::move(value); return {true, object_element}; } diff --git a/include/nlohmann/detail/input/lexer.hpp b/include/nlohmann/detail/input/lexer.hpp index 8042f3c4..0a0c6c74 100644 --- a/include/nlohmann/detail/input/lexer.hpp +++ b/include/nlohmann/detail/input/lexer.hpp @@ -135,7 +135,7 @@ class lexer : public lexer_base static char get_decimal_point() noexcept { const auto* loc = localeconv(); - assert(loc != nullptr); + JSON_ASSERT(loc != nullptr); return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point); } @@ -161,7 +161,7 @@ class lexer : public lexer_base int get_codepoint() { // this function only makes sense after reading `\u` - assert(current == 'u'); + JSON_ASSERT(current == 'u'); int codepoint = 0; const auto factors = { 12u, 8u, 4u, 0u }; @@ -187,7 +187,7 @@ class lexer : public lexer_base } } - assert(0x0000 <= codepoint and codepoint <= 0xFFFF); + JSON_ASSERT(0x0000 <= codepoint and codepoint <= 0xFFFF); return codepoint; } @@ -208,7 +208,7 @@ class lexer : public lexer_base */ bool next_byte_in_range(std::initializer_list ranges) { - assert(ranges.size() == 2 or ranges.size() == 4 or ranges.size() == 6); + JSON_ASSERT(ranges.size() == 2 or ranges.size() == 4 or ranges.size() == 6); add(current); for (auto range = ranges.begin(); range != ranges.end(); ++range) @@ -249,7 +249,7 @@ class lexer : public lexer_base reset(); // we entered the function by reading an open quote - assert(current == '\"'); + JSON_ASSERT(current == '\"'); while (true) { @@ -369,7 +369,7 @@ class lexer : public lexer_base } // result of the above calculation yields a proper codepoint - assert(0x00 <= codepoint and codepoint <= 0x10FFFF); + JSON_ASSERT(0x00 <= codepoint and codepoint <= 0x10FFFF); // translate codepoint into bytes if (codepoint < 0x80) @@ -998,7 +998,7 @@ class lexer : public lexer_base // all other characters are rejected outside scan_number() default: // LCOV_EXCL_LINE - assert(false); // LCOV_EXCL_LINE + JSON_ASSERT(false); // LCOV_EXCL_LINE } scan_number_minus: @@ -1245,7 +1245,7 @@ scan_number_done: const auto x = std::strtoull(token_buffer.data(), &endptr, 10); // we checked the number format before - assert(endptr == token_buffer.data() + token_buffer.size()); + JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size()); if (errno == 0) { @@ -1261,7 +1261,7 @@ scan_number_done: const auto x = std::strtoll(token_buffer.data(), &endptr, 10); // we checked the number format before - assert(endptr == token_buffer.data() + token_buffer.size()); + JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size()); if (errno == 0) { @@ -1278,7 +1278,7 @@ scan_number_done: strtof(value_float, token_buffer.data(), &endptr); // we checked the number format before - assert(endptr == token_buffer.data() + token_buffer.size()); + JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size()); return token_type::value_float; } @@ -1292,7 +1292,7 @@ scan_number_done: token_type scan_literal(const char_type* literal_text, const std::size_t length, token_type return_type) { - assert(std::char_traits::to_char_type(current) == literal_text[0]); + JSON_ASSERT(std::char_traits::to_char_type(current) == literal_text[0]); for (std::size_t i = 1; i < length; ++i) { if (JSON_HEDLEY_UNLIKELY(std::char_traits::to_char_type(get()) != literal_text[i])) @@ -1384,7 +1384,7 @@ scan_number_done: if (JSON_HEDLEY_LIKELY(current != std::char_traits::eof())) { - assert(not token_string.empty()); + JSON_ASSERT(not token_string.empty()); token_string.pop_back(); } } diff --git a/include/nlohmann/detail/input/parser.hpp b/include/nlohmann/detail/input/parser.hpp index c79b492a..b9f7cd84 100644 --- a/include/nlohmann/detail/input/parser.hpp +++ b/include/nlohmann/detail/input/parser.hpp @@ -1,6 +1,5 @@ #pragma once -#include // assert #include // isfinite #include // uint8_t #include // function @@ -383,7 +382,7 @@ class parser // new value, we need to evaluate the new state first. // By setting skip_to_state_evaluation to false, we // are effectively jumping to the beginning of this if. - assert(not states.empty()); + JSON_ASSERT(not states.empty()); states.pop_back(); skip_to_state_evaluation = true; continue; @@ -439,7 +438,7 @@ class parser // new value, we need to evaluate the new state first. // By setting skip_to_state_evaluation to false, we // are effectively jumping to the beginning of this if. - assert(not states.empty()); + JSON_ASSERT(not states.empty()); states.pop_back(); skip_to_state_evaluation = true; continue; diff --git a/include/nlohmann/detail/iterators/iter_impl.hpp b/include/nlohmann/detail/iterators/iter_impl.hpp index 0b79202a..8d7796e1 100644 --- a/include/nlohmann/detail/iterators/iter_impl.hpp +++ b/include/nlohmann/detail/iterators/iter_impl.hpp @@ -85,7 +85,7 @@ class iter_impl */ explicit iter_impl(pointer object) noexcept : m_object(object) { - assert(m_object != nullptr); + JSON_ASSERT(m_object != nullptr); switch (m_object->m_type) { @@ -171,7 +171,7 @@ class iter_impl */ void set_begin() noexcept { - assert(m_object != nullptr); + JSON_ASSERT(m_object != nullptr); switch (m_object->m_type) { @@ -208,7 +208,7 @@ class iter_impl */ void set_end() noexcept { - assert(m_object != nullptr); + JSON_ASSERT(m_object != nullptr); switch (m_object->m_type) { @@ -239,19 +239,19 @@ class iter_impl */ reference operator*() const { - assert(m_object != nullptr); + JSON_ASSERT(m_object != nullptr); switch (m_object->m_type) { case value_t::object: { - assert(m_it.object_iterator != m_object->m_value.object->end()); + JSON_ASSERT(m_it.object_iterator != m_object->m_value.object->end()); return m_it.object_iterator->second; } case value_t::array: { - assert(m_it.array_iterator != m_object->m_value.array->end()); + JSON_ASSERT(m_it.array_iterator != m_object->m_value.array->end()); return *m_it.array_iterator; } @@ -276,19 +276,19 @@ class iter_impl */ pointer operator->() const { - assert(m_object != nullptr); + JSON_ASSERT(m_object != nullptr); switch (m_object->m_type) { case value_t::object: { - assert(m_it.object_iterator != m_object->m_value.object->end()); + JSON_ASSERT(m_it.object_iterator != m_object->m_value.object->end()); return &(m_it.object_iterator->second); } case value_t::array: { - assert(m_it.array_iterator != m_object->m_value.array->end()); + JSON_ASSERT(m_it.array_iterator != m_object->m_value.array->end()); return &*m_it.array_iterator; } @@ -321,7 +321,7 @@ class iter_impl */ iter_impl& operator++() { - assert(m_object != nullptr); + JSON_ASSERT(m_object != nullptr); switch (m_object->m_type) { @@ -364,7 +364,7 @@ class iter_impl */ iter_impl& operator--() { - assert(m_object != nullptr); + JSON_ASSERT(m_object != nullptr); switch (m_object->m_type) { @@ -402,7 +402,7 @@ class iter_impl JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers")); } - assert(m_object != nullptr); + JSON_ASSERT(m_object != nullptr); switch (m_object->m_type) { @@ -438,7 +438,7 @@ class iter_impl JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers")); } - assert(m_object != nullptr); + JSON_ASSERT(m_object != nullptr); switch (m_object->m_type) { @@ -486,7 +486,7 @@ class iter_impl */ iter_impl& operator+=(difference_type i) { - assert(m_object != nullptr); + JSON_ASSERT(m_object != nullptr); switch (m_object->m_type) { @@ -557,7 +557,7 @@ class iter_impl */ difference_type operator-(const iter_impl& other) const { - assert(m_object != nullptr); + JSON_ASSERT(m_object != nullptr); switch (m_object->m_type) { @@ -578,7 +578,7 @@ class iter_impl */ reference operator[](difference_type n) const { - assert(m_object != nullptr); + JSON_ASSERT(m_object != nullptr); switch (m_object->m_type) { @@ -609,7 +609,7 @@ class iter_impl */ const typename object_t::key_type& key() const { - assert(m_object != nullptr); + JSON_ASSERT(m_object != nullptr); if (JSON_HEDLEY_LIKELY(m_object->is_object())) { diff --git a/include/nlohmann/detail/iterators/iteration_proxy.hpp b/include/nlohmann/detail/iterators/iteration_proxy.hpp index 7d0f1e59..b10d0587 100644 --- a/include/nlohmann/detail/iterators/iteration_proxy.hpp +++ b/include/nlohmann/detail/iterators/iteration_proxy.hpp @@ -74,7 +74,7 @@ template class iteration_proxy_value /// return key of the iterator const string_type& key() const { - assert(anchor.m_object != nullptr); + JSON_ASSERT(anchor.m_object != nullptr); switch (anchor.m_object->type()) { diff --git a/include/nlohmann/detail/json_pointer.hpp b/include/nlohmann/detail/json_pointer.hpp index ea14861b..1ac86591 100644 --- a/include/nlohmann/detail/json_pointer.hpp +++ b/include/nlohmann/detail/json_pointer.hpp @@ -1,7 +1,6 @@ #pragma once #include // all_of -#include // assert #include // isdigit #include // max #include // accumulate @@ -781,7 +780,7 @@ class json_pointer pos != std::string::npos; pos = reference_token.find_first_of('~', pos + 1)) { - assert(reference_token[pos] == '~'); + JSON_ASSERT(reference_token[pos] == '~'); // ~ must be followed by 0 or 1 if (JSON_HEDLEY_UNLIKELY(pos == reference_token.size() - 1 or @@ -816,7 +815,7 @@ class json_pointer static void replace_substring(std::string& s, const std::string& f, const std::string& t) { - assert(not f.empty()); + JSON_ASSERT(not f.empty()); for (auto pos = s.find(f); // find first occurrence of f pos != std::string::npos; // make sure f was found s.replace(pos, f.size(), t), // replace with t, and diff --git a/include/nlohmann/detail/macro_scope.hpp b/include/nlohmann/detail/macro_scope.hpp index 46fa8c10..3537768f 100644 --- a/include/nlohmann/detail/macro_scope.hpp +++ b/include/nlohmann/detail/macro_scope.hpp @@ -77,6 +77,12 @@ #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER #endif +// allow to override assert +#if !defined(JSON_ASSERT) + #include // assert + #define JSON_ASSERT(x) assert(x) +#endif + /*! @brief macro to briefly define a mapping between an enum and JSON @def NLOHMANN_JSON_SERIALIZE_ENUM diff --git a/include/nlohmann/detail/macro_unscope.hpp b/include/nlohmann/detail/macro_unscope.hpp index 80b293e7..04415061 100644 --- a/include/nlohmann/detail/macro_unscope.hpp +++ b/include/nlohmann/detail/macro_unscope.hpp @@ -9,6 +9,7 @@ #endif // clean up +#undef JSON_ASSERT #undef JSON_INTERNAL_CATCH #undef JSON_CATCH #undef JSON_THROW diff --git a/include/nlohmann/detail/output/binary_writer.hpp b/include/nlohmann/detail/output/binary_writer.hpp index 3bac0227..844791a0 100644 --- a/include/nlohmann/detail/output/binary_writer.hpp +++ b/include/nlohmann/detail/output/binary_writer.hpp @@ -38,7 +38,7 @@ class binary_writer */ explicit binary_writer(output_adapter_t adapter) : oa(adapter) { - assert(oa); + JSON_ASSERT(oa); } /*! @@ -754,7 +754,7 @@ class binary_writer bool prefix_required = true; if (use_type and not j.m_value.array->empty()) { - assert(use_count); + JSON_ASSERT(use_count); const CharType first_prefix = ubjson_prefix(j.front()); const bool same_prefix = std::all_of(j.begin() + 1, j.end(), [this, first_prefix](const BasicJsonType & v) @@ -798,7 +798,7 @@ class binary_writer if (use_type and not j.m_value.binary->empty()) { - assert(use_count); + JSON_ASSERT(use_count); oa->write_character(to_char_type('$')); oa->write_character('U'); } @@ -842,7 +842,7 @@ class binary_writer bool prefix_required = true; if (use_type and not j.m_value.object->empty()) { - assert(use_count); + JSON_ASSERT(use_count); const CharType first_prefix = ubjson_prefix(j.front()); const bool same_prefix = std::all_of(j.begin(), j.end(), [this, first_prefix](const BasicJsonType & v) @@ -1134,7 +1134,7 @@ class binary_writer // LCOV_EXCL_START default: - assert(false); + JSON_ASSERT(false); return 0ul; // LCOV_EXCL_STOP } @@ -1181,7 +1181,7 @@ class binary_writer // LCOV_EXCL_START default: - assert(false); + JSON_ASSERT(false); return; // LCOV_EXCL_STOP } diff --git a/include/nlohmann/detail/output/serializer.hpp b/include/nlohmann/detail/output/serializer.hpp index c089b94f..808d9368 100644 --- a/include/nlohmann/detail/output/serializer.hpp +++ b/include/nlohmann/detail/output/serializer.hpp @@ -2,7 +2,6 @@ #include // reverse, remove, fill, find, none_of #include // array -#include // assert #include // localeconv, lconv #include // labs, isfinite, isnan, signbit #include // size_t, ptrdiff_t @@ -135,8 +134,8 @@ class serializer } // last element - assert(i != val.m_value.object->cend()); - assert(std::next(i) == val.m_value.object->cend()); + JSON_ASSERT(i != val.m_value.object->cend()); + JSON_ASSERT(std::next(i) == val.m_value.object->cend()); o->write_characters(indent_string.c_str(), new_indent); o->write_character('\"'); dump_escaped(i->first, ensure_ascii); @@ -163,8 +162,8 @@ class serializer } // last element - assert(i != val.m_value.object->cend()); - assert(std::next(i) == val.m_value.object->cend()); + JSON_ASSERT(i != val.m_value.object->cend()); + JSON_ASSERT(std::next(i) == val.m_value.object->cend()); o->write_character('\"'); dump_escaped(i->first, ensure_ascii); o->write_characters("\":", 2); @@ -205,7 +204,7 @@ class serializer } // last element - assert(not val.m_value.array->empty()); + JSON_ASSERT(not val.m_value.array->empty()); o->write_characters(indent_string.c_str(), new_indent); dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent); @@ -226,7 +225,7 @@ class serializer } // last element - assert(not val.m_value.array->empty()); + JSON_ASSERT(not val.m_value.array->empty()); dump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent); o->write_character(']'); @@ -360,7 +359,7 @@ class serializer } default: // LCOV_EXCL_LINE - assert(false); // LCOV_EXCL_LINE + JSON_ASSERT(false); // LCOV_EXCL_LINE } } @@ -559,7 +558,7 @@ class serializer } default: // LCOV_EXCL_LINE - assert(false); // LCOV_EXCL_LINE + JSON_ASSERT(false); // LCOV_EXCL_LINE } break; } @@ -622,7 +621,7 @@ class serializer } default: // LCOV_EXCL_LINE - assert(false); // LCOV_EXCL_LINE + JSON_ASSERT(false); // LCOV_EXCL_LINE } } } @@ -723,7 +722,7 @@ class serializer } // spare 1 byte for '\0' - assert(n_chars < number_buffer.size() - 1); + JSON_ASSERT(n_chars < number_buffer.size() - 1); // jump to the end to generate the string from backward // so we later avoid reversing the result @@ -799,9 +798,9 @@ class serializer std::ptrdiff_t len = (std::snprintf)(number_buffer.data(), number_buffer.size(), "%.*g", d, x); // negative value indicates an error - assert(len > 0); + JSON_ASSERT(len > 0); // check if buffer was large enough - assert(static_cast(len) < number_buffer.size()); + JSON_ASSERT(static_cast(len) < number_buffer.size()); // erase thousands separator if (thousands_sep != '\0') @@ -809,7 +808,7 @@ class serializer const auto end = std::remove(number_buffer.begin(), number_buffer.begin() + len, thousands_sep); std::fill(end, number_buffer.end(), '\0'); - assert((end - number_buffer.begin()) <= len); + JSON_ASSERT((end - number_buffer.begin()) <= len); len = (end - number_buffer.begin()); } @@ -889,7 +888,7 @@ class serializer : (0xFFu >> type) & (byte); std::size_t index = 256u + static_cast(state) * 16u + static_cast(type); - assert(index < 400); + JSON_ASSERT(index < 400); state = utf8d[index]; return state; } @@ -901,7 +900,7 @@ class serializer */ number_unsigned_t remove_sign(number_unsigned_t x) { - assert(false); // LCOV_EXCL_LINE + JSON_ASSERT(false); // LCOV_EXCL_LINE return x; // LCOV_EXCL_LINE } @@ -916,7 +915,7 @@ class serializer */ inline number_unsigned_t remove_sign(number_integer_t x) noexcept { - assert(x < 0 and x < (std::numeric_limits::max)()); + JSON_ASSERT(x < 0 and x < (std::numeric_limits::max)()); return static_cast(-(x + 1)) + 1; } diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index 1dedb809..245fa391 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -35,7 +35,6 @@ SOFTWARE. #define NLOHMANN_JSON_VERSION_PATCH 0 #include // all_of, find, for_each -#include // assert #include // nullptr_t, ptrdiff_t, size_t #include // hash, less #include // initializer_list @@ -924,7 +923,7 @@ class basic_json }; std::unique_ptr object(AllocatorTraits::allocate(alloc, 1), deleter); AllocatorTraits::construct(alloc, object.get(), std::forward(args)...); - assert(object != nullptr); + JSON_ASSERT(object != nullptr); return object.release(); } @@ -1219,10 +1218,10 @@ class basic_json */ void assert_invariant() const noexcept { - assert(m_type != value_t::object or m_value.object != nullptr); - assert(m_type != value_t::array or m_value.array != nullptr); - assert(m_type != value_t::string or m_value.string != nullptr); - assert(m_type != value_t::binary or m_value.binary != nullptr); + JSON_ASSERT(m_type != value_t::object or m_value.object != nullptr); + JSON_ASSERT(m_type != value_t::array or m_value.array != nullptr); + JSON_ASSERT(m_type != value_t::string or m_value.string != nullptr); + JSON_ASSERT(m_type != value_t::binary or m_value.binary != nullptr); } public: @@ -1515,7 +1514,7 @@ class basic_json m_type = value_t::discarded; break; default: // LCOV_EXCL_LINE - assert(false); // LCOV_EXCL_LINE + JSON_ASSERT(false); // LCOV_EXCL_LINE } assert_invariant(); } @@ -1915,8 +1914,8 @@ class basic_json std::is_same::value, int>::type = 0> basic_json(InputIT first, InputIT last) { - assert(first.m_object != nullptr); - assert(last.m_object != nullptr); + JSON_ASSERT(first.m_object != nullptr); + JSON_ASSERT(last.m_object != nullptr); // make sure iterator fits the current value if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object)) @@ -3633,7 +3632,7 @@ class basic_json // const operator[] only works for objects if (JSON_HEDLEY_LIKELY(is_object())) { - assert(m_value.object->find(key) != m_value.object->end()); + JSON_ASSERT(m_value.object->find(key) != m_value.object->end()); return m_value.object->find(key)->second; } @@ -3725,7 +3724,7 @@ class basic_json // at only works for objects if (JSON_HEDLEY_LIKELY(is_object())) { - assert(m_value.object->find(key) != m_value.object->end()); + JSON_ASSERT(m_value.object->find(key) != m_value.object->end()); return m_value.object->find(key)->second; } @@ -5493,7 +5492,7 @@ class basic_json iterator insert_iterator(const_iterator pos, Args&& ... args) { iterator result(this); - assert(m_value.array != nullptr); + JSON_ASSERT(m_value.array != nullptr); auto insert_pos = std::distance(m_value.array->begin(), pos.m_it.array_iterator); m_value.array->insert(pos.m_it.array_iterator, std::forward(args)...); @@ -8258,7 +8257,7 @@ class basic_json // if there exists a parent it cannot be primitive default: // LCOV_EXCL_LINE - assert(false); // LCOV_EXCL_LINE + JSON_ASSERT(false); // LCOV_EXCL_LINE } }; diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 87222900..a2940ed0 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -35,7 +35,6 @@ SOFTWARE. #define NLOHMANN_JSON_VERSION_PATCH 0 #include // all_of, find, for_each -#include // assert #include // nullptr_t, ptrdiff_t, size_t #include // hash, less #include // initializer_list @@ -2105,6 +2104,12 @@ JSON_HEDLEY_DIAGNOSTIC_POP #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER #endif +// allow to override assert +#if !defined(JSON_ASSERT) + #include // assert + #define JSON_ASSERT(x) assert(x) +#endif + /*! @brief macro to briefly define a mapping between an enum and JSON @def NLOHMANN_JSON_SERIALIZE_ENUM @@ -3757,7 +3762,7 @@ template class iteration_proxy_value /// return key of the iterator const string_type& key() const { - assert(anchor.m_object != nullptr); + JSON_ASSERT(anchor.m_object != nullptr); switch (anchor.m_object->type()) { @@ -4451,7 +4456,6 @@ class byte_container_with_subtype : public BinaryType #include // generate_n #include // array -#include // assert #include // ldexp #include // size_t #include // uint8_t, uint16_t, uint32_t, uint64_t @@ -4468,7 +4472,6 @@ class byte_container_with_subtype : public BinaryType #include // array -#include // assert #include // size_t #include //FILE * #include // strlen @@ -4766,13 +4769,13 @@ class wide_string_input_adapter { fill_buffer(); - assert(utf8_bytes_filled > 0); - assert(utf8_bytes_index == 0); + JSON_ASSERT(utf8_bytes_filled > 0); + JSON_ASSERT(utf8_bytes_index == 0); } // use buffer - assert(utf8_bytes_filled > 0); - assert(utf8_bytes_index < utf8_bytes_filled); + JSON_ASSERT(utf8_bytes_filled > 0); + JSON_ASSERT(utf8_bytes_index < utf8_bytes_filled); return utf8_bytes[utf8_bytes_index++]; } @@ -4926,7 +4929,6 @@ class span_input_adapter // #include -#include // assert #include #include // string #include // move @@ -5208,7 +5210,7 @@ class json_sax_dom_parser case 5: JSON_THROW(*dynamic_cast(&ex)); default: - assert(false); + JSON_ASSERT(false); // LCOV_EXCL_STOP } } @@ -5237,7 +5239,7 @@ class json_sax_dom_parser return &root; } - assert(ref_stack.back()->is_array() or ref_stack.back()->is_object()); + JSON_ASSERT(ref_stack.back()->is_array() or ref_stack.back()->is_object()); if (ref_stack.back()->is_array()) { @@ -5245,8 +5247,8 @@ class json_sax_dom_parser return &(ref_stack.back()->m_value.array->back()); } - assert(ref_stack.back()->is_object()); - assert(object_element); + JSON_ASSERT(ref_stack.back()->is_object()); + JSON_ASSERT(object_element); *object_element = BasicJsonType(std::forward(v)); return object_element; } @@ -5375,8 +5377,8 @@ class json_sax_dom_callback_parser *ref_stack.back() = discarded; } - assert(not ref_stack.empty()); - assert(not keep_stack.empty()); + JSON_ASSERT(not ref_stack.empty()); + JSON_ASSERT(not keep_stack.empty()); ref_stack.pop_back(); keep_stack.pop_back(); @@ -5427,8 +5429,8 @@ class json_sax_dom_callback_parser } } - assert(not ref_stack.empty()); - assert(not keep_stack.empty()); + JSON_ASSERT(not ref_stack.empty()); + JSON_ASSERT(not keep_stack.empty()); ref_stack.pop_back(); keep_stack.pop_back(); @@ -5462,7 +5464,7 @@ class json_sax_dom_callback_parser case 5: JSON_THROW(*dynamic_cast(&ex)); default: - assert(false); + JSON_ASSERT(false); // LCOV_EXCL_STOP } } @@ -5493,7 +5495,7 @@ class json_sax_dom_callback_parser template std::pair handle_value(Value&& v, const bool skip_callback = false) { - assert(not keep_stack.empty()); + JSON_ASSERT(not keep_stack.empty()); // do not handle this value if we know it would be added to a discarded // container @@ -5528,7 +5530,7 @@ class json_sax_dom_callback_parser } // we now only expect arrays and objects - assert(ref_stack.back()->is_array() or ref_stack.back()->is_object()); + JSON_ASSERT(ref_stack.back()->is_array() or ref_stack.back()->is_object()); // array if (ref_stack.back()->is_array()) @@ -5538,9 +5540,9 @@ class json_sax_dom_callback_parser } // object - assert(ref_stack.back()->is_object()); + JSON_ASSERT(ref_stack.back()->is_object()); // check if we should store an element for the current key - assert(not key_keep_stack.empty()); + JSON_ASSERT(not key_keep_stack.empty()); const bool store_element = key_keep_stack.back(); key_keep_stack.pop_back(); @@ -5549,7 +5551,7 @@ class json_sax_dom_callback_parser return {false, nullptr}; } - assert(object_element); + JSON_ASSERT(object_element); *object_element = std::move(value); return {true, object_element}; } @@ -5893,7 +5895,7 @@ class binary_reader break; default: // LCOV_EXCL_LINE - assert(false); // LCOV_EXCL_LINE + JSON_ASSERT(false); // LCOV_EXCL_LINE } // strict mode: next byte must be EOF @@ -6501,8 +6503,8 @@ class binary_reader { const int exp = (half >> 10u) & 0x1Fu; const unsigned int mant = half & 0x3FFu; - assert(0 <= exp and exp <= 32); - assert(mant <= 1024); + JSON_ASSERT(0 <= exp and exp <= 32); + JSON_ASSERT(mant <= 1024); switch (exp) { case 0: @@ -8079,7 +8081,7 @@ class binary_reader break; default: // LCOV_EXCL_LINE - assert(false); // LCOV_EXCL_LINE + JSON_ASSERT(false); // LCOV_EXCL_LINE } return error_msg + " " + context + ": " + detail; @@ -8247,7 +8249,7 @@ class lexer : public lexer_base static char get_decimal_point() noexcept { const auto* loc = localeconv(); - assert(loc != nullptr); + JSON_ASSERT(loc != nullptr); return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point); } @@ -8273,7 +8275,7 @@ class lexer : public lexer_base int get_codepoint() { // this function only makes sense after reading `\u` - assert(current == 'u'); + JSON_ASSERT(current == 'u'); int codepoint = 0; const auto factors = { 12u, 8u, 4u, 0u }; @@ -8299,7 +8301,7 @@ class lexer : public lexer_base } } - assert(0x0000 <= codepoint and codepoint <= 0xFFFF); + JSON_ASSERT(0x0000 <= codepoint and codepoint <= 0xFFFF); return codepoint; } @@ -8320,7 +8322,7 @@ class lexer : public lexer_base */ bool next_byte_in_range(std::initializer_list ranges) { - assert(ranges.size() == 2 or ranges.size() == 4 or ranges.size() == 6); + JSON_ASSERT(ranges.size() == 2 or ranges.size() == 4 or ranges.size() == 6); add(current); for (auto range = ranges.begin(); range != ranges.end(); ++range) @@ -8361,7 +8363,7 @@ class lexer : public lexer_base reset(); // we entered the function by reading an open quote - assert(current == '\"'); + JSON_ASSERT(current == '\"'); while (true) { @@ -8481,7 +8483,7 @@ class lexer : public lexer_base } // result of the above calculation yields a proper codepoint - assert(0x00 <= codepoint and codepoint <= 0x10FFFF); + JSON_ASSERT(0x00 <= codepoint and codepoint <= 0x10FFFF); // translate codepoint into bytes if (codepoint < 0x80) @@ -9110,7 +9112,7 @@ class lexer : public lexer_base // all other characters are rejected outside scan_number() default: // LCOV_EXCL_LINE - assert(false); // LCOV_EXCL_LINE + JSON_ASSERT(false); // LCOV_EXCL_LINE } scan_number_minus: @@ -9357,7 +9359,7 @@ scan_number_done: const auto x = std::strtoull(token_buffer.data(), &endptr, 10); // we checked the number format before - assert(endptr == token_buffer.data() + token_buffer.size()); + JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size()); if (errno == 0) { @@ -9373,7 +9375,7 @@ scan_number_done: const auto x = std::strtoll(token_buffer.data(), &endptr, 10); // we checked the number format before - assert(endptr == token_buffer.data() + token_buffer.size()); + JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size()); if (errno == 0) { @@ -9390,7 +9392,7 @@ scan_number_done: strtof(value_float, token_buffer.data(), &endptr); // we checked the number format before - assert(endptr == token_buffer.data() + token_buffer.size()); + JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size()); return token_type::value_float; } @@ -9404,7 +9406,7 @@ scan_number_done: token_type scan_literal(const char_type* literal_text, const std::size_t length, token_type return_type) { - assert(std::char_traits::to_char_type(current) == literal_text[0]); + JSON_ASSERT(std::char_traits::to_char_type(current) == literal_text[0]); for (std::size_t i = 1; i < length; ++i) { if (JSON_HEDLEY_UNLIKELY(std::char_traits::to_char_type(get()) != literal_text[i])) @@ -9496,7 +9498,7 @@ scan_number_done: if (JSON_HEDLEY_LIKELY(current != std::char_traits::eof())) { - assert(not token_string.empty()); + JSON_ASSERT(not token_string.empty()); token_string.pop_back(); } } @@ -9737,7 +9739,6 @@ scan_number_done: // #include -#include // assert #include // isfinite #include // uint8_t #include // function @@ -10127,7 +10128,7 @@ class parser // new value, we need to evaluate the new state first. // By setting skip_to_state_evaluation to false, we // are effectively jumping to the beginning of this if. - assert(not states.empty()); + JSON_ASSERT(not states.empty()); states.pop_back(); skip_to_state_evaluation = true; continue; @@ -10183,7 +10184,7 @@ class parser // new value, we need to evaluate the new state first. // By setting skip_to_state_evaluation to false, we // are effectively jumping to the beginning of this if. - assert(not states.empty()); + JSON_ASSERT(not states.empty()); states.pop_back(); skip_to_state_evaluation = true; continue; @@ -10489,7 +10490,7 @@ class iter_impl */ explicit iter_impl(pointer object) noexcept : m_object(object) { - assert(m_object != nullptr); + JSON_ASSERT(m_object != nullptr); switch (m_object->m_type) { @@ -10575,7 +10576,7 @@ class iter_impl */ void set_begin() noexcept { - assert(m_object != nullptr); + JSON_ASSERT(m_object != nullptr); switch (m_object->m_type) { @@ -10612,7 +10613,7 @@ class iter_impl */ void set_end() noexcept { - assert(m_object != nullptr); + JSON_ASSERT(m_object != nullptr); switch (m_object->m_type) { @@ -10643,19 +10644,19 @@ class iter_impl */ reference operator*() const { - assert(m_object != nullptr); + JSON_ASSERT(m_object != nullptr); switch (m_object->m_type) { case value_t::object: { - assert(m_it.object_iterator != m_object->m_value.object->end()); + JSON_ASSERT(m_it.object_iterator != m_object->m_value.object->end()); return m_it.object_iterator->second; } case value_t::array: { - assert(m_it.array_iterator != m_object->m_value.array->end()); + JSON_ASSERT(m_it.array_iterator != m_object->m_value.array->end()); return *m_it.array_iterator; } @@ -10680,19 +10681,19 @@ class iter_impl */ pointer operator->() const { - assert(m_object != nullptr); + JSON_ASSERT(m_object != nullptr); switch (m_object->m_type) { case value_t::object: { - assert(m_it.object_iterator != m_object->m_value.object->end()); + JSON_ASSERT(m_it.object_iterator != m_object->m_value.object->end()); return &(m_it.object_iterator->second); } case value_t::array: { - assert(m_it.array_iterator != m_object->m_value.array->end()); + JSON_ASSERT(m_it.array_iterator != m_object->m_value.array->end()); return &*m_it.array_iterator; } @@ -10725,7 +10726,7 @@ class iter_impl */ iter_impl& operator++() { - assert(m_object != nullptr); + JSON_ASSERT(m_object != nullptr); switch (m_object->m_type) { @@ -10768,7 +10769,7 @@ class iter_impl */ iter_impl& operator--() { - assert(m_object != nullptr); + JSON_ASSERT(m_object != nullptr); switch (m_object->m_type) { @@ -10806,7 +10807,7 @@ class iter_impl JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers")); } - assert(m_object != nullptr); + JSON_ASSERT(m_object != nullptr); switch (m_object->m_type) { @@ -10842,7 +10843,7 @@ class iter_impl JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers")); } - assert(m_object != nullptr); + JSON_ASSERT(m_object != nullptr); switch (m_object->m_type) { @@ -10890,7 +10891,7 @@ class iter_impl */ iter_impl& operator+=(difference_type i) { - assert(m_object != nullptr); + JSON_ASSERT(m_object != nullptr); switch (m_object->m_type) { @@ -10961,7 +10962,7 @@ class iter_impl */ difference_type operator-(const iter_impl& other) const { - assert(m_object != nullptr); + JSON_ASSERT(m_object != nullptr); switch (m_object->m_type) { @@ -10982,7 +10983,7 @@ class iter_impl */ reference operator[](difference_type n) const { - assert(m_object != nullptr); + JSON_ASSERT(m_object != nullptr); switch (m_object->m_type) { @@ -11013,7 +11014,7 @@ class iter_impl */ const typename object_t::key_type& key() const { - assert(m_object != nullptr); + JSON_ASSERT(m_object != nullptr); if (JSON_HEDLEY_LIKELY(m_object->is_object())) { @@ -11170,7 +11171,6 @@ class json_reverse_iterator : public std::reverse_iterator #include // all_of -#include // assert #include // isdigit #include // max #include // accumulate @@ -11953,7 +11953,7 @@ class json_pointer pos != std::string::npos; pos = reference_token.find_first_of('~', pos + 1)) { - assert(reference_token[pos] == '~'); + JSON_ASSERT(reference_token[pos] == '~'); // ~ must be followed by 0 or 1 if (JSON_HEDLEY_UNLIKELY(pos == reference_token.size() - 1 or @@ -11988,7 +11988,7 @@ class json_pointer static void replace_substring(std::string& s, const std::string& f, const std::string& t) { - assert(not f.empty()); + JSON_ASSERT(not f.empty()); for (auto pos = s.find(f); // find first occurrence of f pos != std::string::npos; // make sure f was found s.replace(pos, f.size(), t), // replace with t, and @@ -12400,7 +12400,7 @@ class binary_writer */ explicit binary_writer(output_adapter_t adapter) : oa(adapter) { - assert(oa); + JSON_ASSERT(oa); } /*! @@ -13116,7 +13116,7 @@ class binary_writer bool prefix_required = true; if (use_type and not j.m_value.array->empty()) { - assert(use_count); + JSON_ASSERT(use_count); const CharType first_prefix = ubjson_prefix(j.front()); const bool same_prefix = std::all_of(j.begin() + 1, j.end(), [this, first_prefix](const BasicJsonType & v) @@ -13160,7 +13160,7 @@ class binary_writer if (use_type and not j.m_value.binary->empty()) { - assert(use_count); + JSON_ASSERT(use_count); oa->write_character(to_char_type('$')); oa->write_character('U'); } @@ -13204,7 +13204,7 @@ class binary_writer bool prefix_required = true; if (use_type and not j.m_value.object->empty()) { - assert(use_count); + JSON_ASSERT(use_count); const CharType first_prefix = ubjson_prefix(j.front()); const bool same_prefix = std::all_of(j.begin(), j.end(), [this, first_prefix](const BasicJsonType & v) @@ -13496,7 +13496,7 @@ class binary_writer // LCOV_EXCL_START default: - assert(false); + JSON_ASSERT(false); return 0ul; // LCOV_EXCL_STOP } @@ -13543,7 +13543,7 @@ class binary_writer // LCOV_EXCL_START default: - assert(false); + JSON_ASSERT(false); return; // LCOV_EXCL_STOP } @@ -13935,7 +13935,6 @@ class binary_writer #include // reverse, remove, fill, find, none_of #include // array -#include // assert #include // localeconv, lconv #include // labs, isfinite, isnan, signbit #include // size_t, ptrdiff_t @@ -13952,7 +13951,6 @@ class binary_writer #include // array -#include // assert #include // signbit, isfinite #include // intN_t, uintN_t #include // memcpy, memmove @@ -14016,8 +14014,8 @@ struct diyfp // f * 2^e */ static diyfp sub(const diyfp& x, const diyfp& y) noexcept { - assert(x.e == y.e); - assert(x.f >= y.f); + JSON_ASSERT(x.e == y.e); + JSON_ASSERT(x.f >= y.f); return {x.f - y.f, x.e}; } @@ -14093,7 +14091,7 @@ struct diyfp // f * 2^e */ static diyfp normalize(diyfp x) noexcept { - assert(x.f != 0); + JSON_ASSERT(x.f != 0); while ((x.f >> 63u) == 0) { @@ -14112,8 +14110,8 @@ struct diyfp // f * 2^e { const int delta = x.e - target_exponent; - assert(delta >= 0); - assert(((x.f << delta) >> delta) == x.f); + JSON_ASSERT(delta >= 0); + JSON_ASSERT(((x.f << delta) >> delta) == x.f); return {x.f << delta, target_exponent}; } @@ -14135,8 +14133,8 @@ boundaries. template boundaries compute_boundaries(FloatType value) { - assert(std::isfinite(value)); - assert(value > 0); + JSON_ASSERT(std::isfinite(value)); + JSON_ASSERT(value > 0); // Convert the IEEE representation into a diyfp. // @@ -14416,18 +14414,18 @@ inline cached_power get_cached_power_for_binary_exponent(int e) // k = ceil((kAlpha - e - 1) * 0.30102999566398114) // for |e| <= 1500, but doesn't require floating-point operations. // NB: log_10(2) ~= 78913 / 2^18 - assert(e >= -1500); - assert(e <= 1500); + JSON_ASSERT(e >= -1500); + JSON_ASSERT(e <= 1500); const int f = kAlpha - e - 1; const int k = (f * 78913) / (1 << 18) + static_cast(f > 0); const int index = (-kCachedPowersMinDecExp + k + (kCachedPowersDecStep - 1)) / kCachedPowersDecStep; - assert(index >= 0); - assert(static_cast(index) < kCachedPowers.size()); + JSON_ASSERT(index >= 0); + JSON_ASSERT(static_cast(index) < kCachedPowers.size()); const cached_power cached = kCachedPowers[static_cast(index)]; - assert(kAlpha <= cached.e + e + 64); - assert(kGamma >= cached.e + e + 64); + JSON_ASSERT(kAlpha <= cached.e + e + 64); + JSON_ASSERT(kGamma >= cached.e + e + 64); return cached; } @@ -14495,10 +14493,10 @@ inline int find_largest_pow10(const std::uint32_t n, std::uint32_t& pow10) inline void grisu2_round(char* buf, int len, std::uint64_t dist, std::uint64_t delta, std::uint64_t rest, std::uint64_t ten_k) { - assert(len >= 1); - assert(dist <= delta); - assert(rest <= delta); - assert(ten_k > 0); + JSON_ASSERT(len >= 1); + JSON_ASSERT(dist <= delta); + JSON_ASSERT(rest <= delta); + JSON_ASSERT(ten_k > 0); // <--------------------------- delta ----> // <---- dist ---------> @@ -14523,7 +14521,7 @@ inline void grisu2_round(char* buf, int len, std::uint64_t dist, std::uint64_t d and delta - rest >= ten_k and (rest + ten_k < dist or dist - rest > rest + ten_k - dist)) { - assert(buf[len - 1] != '0'); + JSON_ASSERT(buf[len - 1] != '0'); buf[len - 1]--; rest += ten_k; } @@ -14551,8 +14549,8 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent, // Grisu2 generates the digits of M+ from left to right and stops as soon as // V is in [M-,M+]. - assert(M_plus.e >= kAlpha); - assert(M_plus.e <= kGamma); + JSON_ASSERT(M_plus.e >= kAlpha); + JSON_ASSERT(M_plus.e <= kGamma); std::uint64_t delta = diyfp::sub(M_plus, M_minus).f; // (significand of (M+ - M-), implicit exponent is e) std::uint64_t dist = diyfp::sub(M_plus, w ).f; // (significand of (M+ - w ), implicit exponent is e) @@ -14573,7 +14571,7 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent, // // Generate the digits of the integral part p1 = d[n-1]...d[1]d[0] - assert(p1 > 0); + JSON_ASSERT(p1 > 0); std::uint32_t pow10; const int k = find_largest_pow10(p1, pow10); @@ -14609,7 +14607,7 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent, // M+ = buffer * 10^n + (d * 10^(n-1) + r) + p2 * 2^e // = (buffer * 10 + d) * 10^(n-1) + (r + p2 * 2^e) // - assert(d <= 9); + JSON_ASSERT(d <= 9); buffer[length++] = static_cast('0' + d); // buffer := buffer * 10 + d // // M+ = buffer * 10^(n-1) + (r + p2 * 2^e) @@ -14696,7 +14694,7 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent, // // and stop as soon as 10^-m * r * 2^e <= delta * 2^e - assert(p2 > delta); + JSON_ASSERT(p2 > delta); int m = 0; for (;;) @@ -14707,7 +14705,7 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent, // = buffer * 10^-m + 10^-m * (1/10 * (10 * p2) ) * 2^e // = buffer * 10^-m + 10^-m * (1/10 * ((10*p2 div 2^-e) * 2^-e + (10*p2 mod 2^-e)) * 2^e // - assert(p2 <= (std::numeric_limits::max)() / 10); + JSON_ASSERT(p2 <= (std::numeric_limits::max)() / 10); p2 *= 10; const std::uint64_t d = p2 >> -one.e; // d = (10 * p2) div 2^-e const std::uint64_t r = p2 & (one.f - 1); // r = (10 * p2) mod 2^-e @@ -14716,7 +14714,7 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent, // = buffer * 10^-m + 10^-m * (1/10 * (d + r * 2^e)) // = (buffer * 10 + d) * 10^(-m-1) + 10^(-m-1) * r * 2^e // - assert(d <= 9); + JSON_ASSERT(d <= 9); buffer[length++] = static_cast('0' + d); // buffer := buffer * 10 + d // // M+ = buffer * 10^(-m-1) + 10^(-m-1) * r * 2^e @@ -14777,8 +14775,8 @@ JSON_HEDLEY_NON_NULL(1) inline void grisu2(char* buf, int& len, int& decimal_exponent, diyfp m_minus, diyfp v, diyfp m_plus) { - assert(m_plus.e == m_minus.e); - assert(m_plus.e == v.e); + JSON_ASSERT(m_plus.e == m_minus.e); + JSON_ASSERT(m_plus.e == v.e); // --------(-----------------------+-----------------------)-------- (A) // m- v m+ @@ -14839,8 +14837,8 @@ void grisu2(char* buf, int& len, int& decimal_exponent, FloatType value) static_assert(diyfp::kPrecision >= std::numeric_limits::digits + 3, "internal error: not enough precision"); - assert(std::isfinite(value)); - assert(value > 0); + JSON_ASSERT(std::isfinite(value)); + JSON_ASSERT(value > 0); // If the neighbors (and boundaries) of 'value' are always computed for double-precision // numbers, all float's can be recovered using strtod (and strtof). However, the resulting @@ -14876,8 +14874,8 @@ JSON_HEDLEY_NON_NULL(1) JSON_HEDLEY_RETURNS_NON_NULL inline char* append_exponent(char* buf, int e) { - assert(e > -1000); - assert(e < 1000); + JSON_ASSERT(e > -1000); + JSON_ASSERT(e < 1000); if (e < 0) { @@ -14929,8 +14927,8 @@ JSON_HEDLEY_RETURNS_NON_NULL inline char* format_buffer(char* buf, int len, int decimal_exponent, int min_exp, int max_exp) { - assert(min_exp < 0); - assert(max_exp > 0); + JSON_ASSERT(min_exp < 0); + JSON_ASSERT(max_exp > 0); const int k = len; const int n = len + decimal_exponent; @@ -14956,7 +14954,7 @@ inline char* format_buffer(char* buf, int len, int decimal_exponent, // dig.its // len <= max_digits10 + 1 - assert(k > n); + JSON_ASSERT(k > n); std::memmove(buf + (static_cast(n) + 1), buf + n, static_cast(k) - static_cast(n)); buf[n] = '.'; @@ -15014,7 +15012,7 @@ JSON_HEDLEY_RETURNS_NON_NULL char* to_chars(char* first, const char* last, FloatType value) { static_cast(last); // maybe unused - fix warning - assert(std::isfinite(value)); + JSON_ASSERT(std::isfinite(value)); // Use signbit(value) instead of (value < 0) since signbit works for -0. if (std::signbit(value)) @@ -15032,7 +15030,7 @@ char* to_chars(char* first, const char* last, FloatType value) return first; } - assert(last - first >= std::numeric_limits::max_digits10); + JSON_ASSERT(last - first >= std::numeric_limits::max_digits10); // Compute v = buffer * 10^decimal_exponent. // The decimal digits are stored in the buffer, which needs to be interpreted @@ -15042,16 +15040,16 @@ char* to_chars(char* first, const char* last, FloatType value) int decimal_exponent = 0; dtoa_impl::grisu2(first, len, decimal_exponent, value); - assert(len <= std::numeric_limits::max_digits10); + JSON_ASSERT(len <= std::numeric_limits::max_digits10); // Format the buffer like printf("%.*g", prec, value) constexpr int kMinExp = -4; // Use digits10 here to increase compatibility with version 2. constexpr int kMaxExp = std::numeric_limits::digits10; - assert(last - first >= kMaxExp + 2); - assert(last - first >= 2 + (-kMinExp - 1) + std::numeric_limits::max_digits10); - assert(last - first >= std::numeric_limits::max_digits10 + 6); + JSON_ASSERT(last - first >= kMaxExp + 2); + JSON_ASSERT(last - first >= 2 + (-kMinExp - 1) + std::numeric_limits::max_digits10); + JSON_ASSERT(last - first >= std::numeric_limits::max_digits10 + 6); return dtoa_impl::format_buffer(first, len, decimal_exponent, kMinExp, kMaxExp); } @@ -15185,8 +15183,8 @@ class serializer } // last element - assert(i != val.m_value.object->cend()); - assert(std::next(i) == val.m_value.object->cend()); + JSON_ASSERT(i != val.m_value.object->cend()); + JSON_ASSERT(std::next(i) == val.m_value.object->cend()); o->write_characters(indent_string.c_str(), new_indent); o->write_character('\"'); dump_escaped(i->first, ensure_ascii); @@ -15213,8 +15211,8 @@ class serializer } // last element - assert(i != val.m_value.object->cend()); - assert(std::next(i) == val.m_value.object->cend()); + JSON_ASSERT(i != val.m_value.object->cend()); + JSON_ASSERT(std::next(i) == val.m_value.object->cend()); o->write_character('\"'); dump_escaped(i->first, ensure_ascii); o->write_characters("\":", 2); @@ -15255,7 +15253,7 @@ class serializer } // last element - assert(not val.m_value.array->empty()); + JSON_ASSERT(not val.m_value.array->empty()); o->write_characters(indent_string.c_str(), new_indent); dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent); @@ -15276,7 +15274,7 @@ class serializer } // last element - assert(not val.m_value.array->empty()); + JSON_ASSERT(not val.m_value.array->empty()); dump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent); o->write_character(']'); @@ -15410,7 +15408,7 @@ class serializer } default: // LCOV_EXCL_LINE - assert(false); // LCOV_EXCL_LINE + JSON_ASSERT(false); // LCOV_EXCL_LINE } } @@ -15609,7 +15607,7 @@ class serializer } default: // LCOV_EXCL_LINE - assert(false); // LCOV_EXCL_LINE + JSON_ASSERT(false); // LCOV_EXCL_LINE } break; } @@ -15672,7 +15670,7 @@ class serializer } default: // LCOV_EXCL_LINE - assert(false); // LCOV_EXCL_LINE + JSON_ASSERT(false); // LCOV_EXCL_LINE } } } @@ -15773,7 +15771,7 @@ class serializer } // spare 1 byte for '\0' - assert(n_chars < number_buffer.size() - 1); + JSON_ASSERT(n_chars < number_buffer.size() - 1); // jump to the end to generate the string from backward // so we later avoid reversing the result @@ -15849,9 +15847,9 @@ class serializer std::ptrdiff_t len = (std::snprintf)(number_buffer.data(), number_buffer.size(), "%.*g", d, x); // negative value indicates an error - assert(len > 0); + JSON_ASSERT(len > 0); // check if buffer was large enough - assert(static_cast(len) < number_buffer.size()); + JSON_ASSERT(static_cast(len) < number_buffer.size()); // erase thousands separator if (thousands_sep != '\0') @@ -15859,7 +15857,7 @@ class serializer const auto end = std::remove(number_buffer.begin(), number_buffer.begin() + len, thousands_sep); std::fill(end, number_buffer.end(), '\0'); - assert((end - number_buffer.begin()) <= len); + JSON_ASSERT((end - number_buffer.begin()) <= len); len = (end - number_buffer.begin()); } @@ -15939,7 +15937,7 @@ class serializer : (0xFFu >> type) & (byte); std::size_t index = 256u + static_cast(state) * 16u + static_cast(type); - assert(index < 400); + JSON_ASSERT(index < 400); state = utf8d[index]; return state; } @@ -15951,7 +15949,7 @@ class serializer */ number_unsigned_t remove_sign(number_unsigned_t x) { - assert(false); // LCOV_EXCL_LINE + JSON_ASSERT(false); // LCOV_EXCL_LINE return x; // LCOV_EXCL_LINE } @@ -15966,7 +15964,7 @@ class serializer */ inline number_unsigned_t remove_sign(number_integer_t x) noexcept { - assert(x < 0 and x < (std::numeric_limits::max)()); + JSON_ASSERT(x < 0 and x < (std::numeric_limits::max)()); return static_cast(-(x + 1)) + 1; } @@ -16854,7 +16852,7 @@ class basic_json }; std::unique_ptr object(AllocatorTraits::allocate(alloc, 1), deleter); AllocatorTraits::construct(alloc, object.get(), std::forward(args)...); - assert(object != nullptr); + JSON_ASSERT(object != nullptr); return object.release(); } @@ -17149,10 +17147,10 @@ class basic_json */ void assert_invariant() const noexcept { - assert(m_type != value_t::object or m_value.object != nullptr); - assert(m_type != value_t::array or m_value.array != nullptr); - assert(m_type != value_t::string or m_value.string != nullptr); - assert(m_type != value_t::binary or m_value.binary != nullptr); + JSON_ASSERT(m_type != value_t::object or m_value.object != nullptr); + JSON_ASSERT(m_type != value_t::array or m_value.array != nullptr); + JSON_ASSERT(m_type != value_t::string or m_value.string != nullptr); + JSON_ASSERT(m_type != value_t::binary or m_value.binary != nullptr); } public: @@ -17445,7 +17443,7 @@ class basic_json m_type = value_t::discarded; break; default: // LCOV_EXCL_LINE - assert(false); // LCOV_EXCL_LINE + JSON_ASSERT(false); // LCOV_EXCL_LINE } assert_invariant(); } @@ -17845,8 +17843,8 @@ class basic_json std::is_same::value, int>::type = 0> basic_json(InputIT first, InputIT last) { - assert(first.m_object != nullptr); - assert(last.m_object != nullptr); + JSON_ASSERT(first.m_object != nullptr); + JSON_ASSERT(last.m_object != nullptr); // make sure iterator fits the current value if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object)) @@ -19563,7 +19561,7 @@ class basic_json // const operator[] only works for objects if (JSON_HEDLEY_LIKELY(is_object())) { - assert(m_value.object->find(key) != m_value.object->end()); + JSON_ASSERT(m_value.object->find(key) != m_value.object->end()); return m_value.object->find(key)->second; } @@ -19655,7 +19653,7 @@ class basic_json // at only works for objects if (JSON_HEDLEY_LIKELY(is_object())) { - assert(m_value.object->find(key) != m_value.object->end()); + JSON_ASSERT(m_value.object->find(key) != m_value.object->end()); return m_value.object->find(key)->second; } @@ -21423,7 +21421,7 @@ class basic_json iterator insert_iterator(const_iterator pos, Args&& ... args) { iterator result(this); - assert(m_value.array != nullptr); + JSON_ASSERT(m_value.array != nullptr); auto insert_pos = std::distance(m_value.array->begin(), pos.m_it.array_iterator); m_value.array->insert(pos.m_it.array_iterator, std::forward(args)...); @@ -24188,7 +24186,7 @@ class basic_json // if there exists a parent it cannot be primitive default: // LCOV_EXCL_LINE - assert(false); // LCOV_EXCL_LINE + JSON_ASSERT(false); // LCOV_EXCL_LINE } }; @@ -24723,6 +24721,7 @@ inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std #endif // clean up +#undef JSON_ASSERT #undef JSON_INTERNAL_CATCH #undef JSON_CATCH #undef JSON_THROW From efcc826ecb9b55893397f749e5514316ba8629bb Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Mon, 6 Jul 2020 12:37:39 +0200 Subject: [PATCH 08/18] :rotating_light: fix warning --- Makefile | 2 +- README.md | 4 ++-- test/src/unit-udt_macro.cpp | 46 ++++++++++++++++++------------------- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/Makefile b/Makefile index 8579fb5d..ff62d6e7 100644 --- a/Makefile +++ b/Makefile @@ -253,7 +253,7 @@ pedantic_gcc: -Wmismatched-tags \ -Wmissing-attributes \ -Wmissing-braces \ - -Wmissing-declarations \ + -Wno-missing-declarations \ -Wmissing-field-initializers \ -Wmissing-include-dirs \ -Wmissing-profile \ diff --git a/README.md b/README.md index 6d21e2d8..3bb92d38 100644 --- a/README.md +++ b/README.md @@ -886,7 +886,7 @@ The `to_json`/`from_json` functions for the `person` struct above can be created ```cpp namespace ns { - NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(person, name, address, age); + NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(person, name, address, age) } ``` @@ -901,7 +901,7 @@ namespace ns { int postcode; public: - NLOHMANN_DEFINE_TYPE_INTRUSIVE(address, street, housenumber, postcode); + NLOHMANN_DEFINE_TYPE_INTRUSIVE(address, street, housenumber, postcode) }; } ``` diff --git a/test/src/unit-udt_macro.cpp b/test/src/unit-udt_macro.cpp index 4535ae5b..a6b66e95 100644 --- a/test/src/unit-udt_macro.cpp +++ b/test/src/unit-udt_macro.cpp @@ -37,9 +37,9 @@ namespace persons class person_with_private_data { private: - std::string name; + std::string name = ""; int age = 0; - json metadata; + json metadata = nullptr; public: bool operator==(const person_with_private_data& rhs) const @@ -48,21 +48,21 @@ class person_with_private_data } person_with_private_data() = default; - person_with_private_data(std::string name, int age, json metadata) - : name(std::move(name)) - , age(age) - , metadata(std::move(metadata)) + person_with_private_data(std::string name_, int age_, json metadata_) + : name(std::move(name_)) + , age(age_) + , metadata(std::move(metadata_)) {} - NLOHMANN_DEFINE_TYPE_INTRUSIVE(person_with_private_data, age, name, metadata); + NLOHMANN_DEFINE_TYPE_INTRUSIVE(person_with_private_data, age, name, metadata) }; class person_without_private_data_1 { public: - std::string name; - int age = 0; - json metadata; + std::string name = ""; + int age = 0; + json metadata = nullptr; bool operator==(const person_without_private_data_1& rhs) const { @@ -70,21 +70,21 @@ class person_without_private_data_1 } person_without_private_data_1() = default; - person_without_private_data_1(std::string name, int age, json metadata) - : name(std::move(name)) - , age(age) - , metadata(std::move(metadata)) + person_without_private_data_1(std::string name_, int age_, json metadata_) + : name(std::move(name_)) + , age(age_) + , metadata(std::move(metadata_)) {} - NLOHMANN_DEFINE_TYPE_INTRUSIVE(person_without_private_data_1, age, name, metadata); + NLOHMANN_DEFINE_TYPE_INTRUSIVE(person_without_private_data_1, age, name, metadata) }; class person_without_private_data_2 { public: - std::string name; - int age = 0; - json metadata; + std::string name = ""; + int age = 0; + json metadata = nullptr; bool operator==(const person_without_private_data_2& rhs) const { @@ -92,14 +92,14 @@ class person_without_private_data_2 } person_without_private_data_2() = default; - person_without_private_data_2(std::string name, int age, json metadata) - : name(std::move(name)) - , age(age) - , metadata(std::move(metadata)) + person_without_private_data_2(std::string name_, int age_, json metadata_) + : name(std::move(name_)) + , age(age_) + , metadata(std::move(metadata_)) {} }; -NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(person_without_private_data_2, age, name, metadata); +NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(person_without_private_data_2, age, name, metadata) } // namespace persons TEST_CASE_TEMPLATE("Serialization/deserialization via NLOHMANN_DEFINE_TYPE_INTRUSIVE", T, From ba8174041e66038c4c02814ecbf2f8e062f2291c Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Mon, 6 Jul 2020 12:52:48 +0200 Subject: [PATCH 09/18] :white_check_mark: add test case for JSON_ASSERT --- test/CMakeLists.txt | 1 + test/src/unit-assert_macro.cpp | 50 ++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 test/src/unit-assert_macro.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8434f78d..43af37d5 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -95,6 +95,7 @@ set(files src/unit-algorithms.cpp src/unit-allocator.cpp src/unit-alt-string.cpp + src/unit-assert_macro.cpp src/unit-bson.cpp src/unit-capacity.cpp src/unit-cbor.cpp diff --git a/test/src/unit-assert_macro.cpp b/test/src/unit-assert_macro.cpp new file mode 100644 index 00000000..009a2b0b --- /dev/null +++ b/test/src/unit-assert_macro.cpp @@ -0,0 +1,50 @@ +/* + __ _____ _____ _____ + __| | __| | | | JSON for Modern C++ (test suite) +| | |__ | | | | | | version 3.8.0 +|_____|_____|_____|_|___| https://github.com/nlohmann/json + +Licensed under the MIT License . +SPDX-License-Identifier: MIT +Copyright (c) 2013-2019 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. +*/ + +#include "doctest_compatibility.h" + +/// global variable to record side effect of assert calls +int assert_counter = 0; + +/// set failure variable to true instead of calling assert(x) +#define JSON_ASSERT(x) if (!(x)) ++assert_counter; + +#include +using nlohmann::json; + +TEST_CASE("JSON_ASSERT(x)") +{ + const json j = {{"bar", 1}}; + CHECK(assert_counter == 0); + + // accessing non-exising key in const value would assert + j["foo"] == 1; + + CHECK(assert_counter == 1); +} \ No newline at end of file From 28ef87370be43ee4ea0d35c33097202c2d71fd2e Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Mon, 6 Jul 2020 13:19:06 +0200 Subject: [PATCH 10/18] :rotating_light: fix warning --- Makefile | 2 ++ test/src/unit-assert_macro.cpp | 25 +++++++++++++++++-------- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index ff62d6e7..3d296baf 100644 --- a/Makefile +++ b/Makefile @@ -97,6 +97,7 @@ doctest: # -Wno-exit-time-destructors: warning in json code triggered by NLOHMANN_JSON_SERIALIZE_ENUM # -Wno-float-equal: not all comparisons in the tests can be replaced by Approx # -Wno-keyword-macro: unit-tests use "#define private public" +# -Wno-missing-prototypes: for NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE # -Wno-padded: padding is nothing to warn about # -Wno-range-loop-analysis: items tests "for(const auto i...)" # -Wno-switch-enum -Wno-covered-switch-default: pedantic/contradicting warnings about switches @@ -113,6 +114,7 @@ pedantic_clang: -Wno-exit-time-destructors \ -Wno-float-equal \ -Wno-keyword-macro \ + -Wno-missing-prototypes \ -Wno-padded \ -Wno-range-loop-analysis \ -Wno-switch-enum -Wno-covered-switch-default \ diff --git a/test/src/unit-assert_macro.cpp b/test/src/unit-assert_macro.cpp index 009a2b0b..c5cd3a01 100644 --- a/test/src/unit-assert_macro.cpp +++ b/test/src/unit-assert_macro.cpp @@ -27,24 +27,33 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +// avoid warning when assert does not abort +#if defined(__GNUC__) + #pragma GCC diagnostic ignored "-Wstrict-overflow" +#endif + #include "doctest_compatibility.h" /// global variable to record side effect of assert calls -int assert_counter = 0; +static int assert_counter; /// set failure variable to true instead of calling assert(x) -#define JSON_ASSERT(x) if (!(x)) ++assert_counter; +#define JSON_ASSERT(x) {if (!(x)) ++assert_counter; } #include using nlohmann::json; TEST_CASE("JSON_ASSERT(x)") { - const json j = {{"bar", 1}}; - CHECK(assert_counter == 0); + assert_counter = 0; + const json j = {{"bar", 1}}; + CHECK(assert_counter == 0); - // accessing non-exising key in const value would assert - j["foo"] == 1; + // accessing non-existing key in const value would assert + if (j["foo"] == 1) + { + CHECK(true); + } - CHECK(assert_counter == 1); -} \ No newline at end of file + CHECK(assert_counter == 1); +} From d019ddfcdb26ee08cd30bf85a10e2a37703f1c56 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Wed, 8 Jul 2020 12:25:53 +0200 Subject: [PATCH 11/18] :construction_worker: add code scanning --- .github/workflows/codeql-analysis.yml | 54 +++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 .github/workflows/codeql-analysis.yml diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 00000000..5ee44a04 --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,54 @@ +name: "Code scanning - action" + +on: + push: + branches: [develop, ] + pull_request: + # The branches below must be a subset of the branches above + branches: [develop] + schedule: + - cron: '0 19 * * 1' + +jobs: + CodeQL-Build: + + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + with: + # We must fetch at least the immediate parents so that if this is + # a pull request then we can checkout the head. + fetch-depth: 2 + + # If this run was triggered by a pull request event, then checkout + # the head of the pull request instead of the merge commit. + - run: git checkout HEAD^2 + if: ${{ github.event_name == 'pull_request' }} + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + # Override language selection by uncommenting this and choosing your languages + # with: + # languages: go, javascript, csharp, python, cpp, java + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v1 + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl + + # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 From 1b04092c5c724941e75ed7b993440cec80e318b8 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Wed, 8 Jul 2020 12:38:46 +0200 Subject: [PATCH 12/18] :white_check_mark: fix test --- test/src/unit-assert_macro.cpp | 19 ++++++++++--------- test/src/unit-udt_macro.cpp | 12 ++++++------ 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/test/src/unit-assert_macro.cpp b/test/src/unit-assert_macro.cpp index c5cd3a01..416cda23 100644 --- a/test/src/unit-assert_macro.cpp +++ b/test/src/unit-assert_macro.cpp @@ -45,15 +45,16 @@ using nlohmann::json; TEST_CASE("JSON_ASSERT(x)") { - assert_counter = 0; - const json j = {{"bar", 1}}; - CHECK(assert_counter == 0); - - // accessing non-existing key in const value would assert - if (j["foo"] == 1) + SECTION("basic_json(first, second)") { - CHECK(true); - } + assert_counter = 0; + CHECK(assert_counter == 0); - CHECK(assert_counter == 1); + json::iterator it; + json j; + + CHECK_THROWS_WITH_AS(json(it, j.end()), "[json.exception.invalid_iterator.201] iterators are not compatible", json::invalid_iterator); + + CHECK(assert_counter == 1); + } } diff --git a/test/src/unit-udt_macro.cpp b/test/src/unit-udt_macro.cpp index a6b66e95..90d5e1cc 100644 --- a/test/src/unit-udt_macro.cpp +++ b/test/src/unit-udt_macro.cpp @@ -60,9 +60,9 @@ class person_with_private_data class person_without_private_data_1 { public: - std::string name = ""; - int age = 0; - json metadata = nullptr; + std::string name = ""; + int age = 0; + json metadata = nullptr; bool operator==(const person_without_private_data_1& rhs) const { @@ -82,9 +82,9 @@ class person_without_private_data_1 class person_without_private_data_2 { public: - std::string name = ""; - int age = 0; - json metadata = nullptr; + std::string name = ""; + int age = 0; + json metadata = nullptr; bool operator==(const person_without_private_data_2& rhs) const { From e3e9ccfc027c26b75234ce1b681bb93929035563 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Wed, 8 Jul 2020 14:02:28 +0200 Subject: [PATCH 13/18] :ambulance: fix regression from #2181 --- include/nlohmann/json.hpp | 12 ++++++------ single_include/nlohmann/json.hpp | 12 ++++++------ test/src/unit-regression.cpp | 9 +++++++++ test/src/unit-udt_macro.cpp | 12 ++++++------ 4 files changed, 27 insertions(+), 18 deletions(-) diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index 1dedb809..8a3957a6 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -3785,7 +3785,7 @@ class basic_json template::value and not std::is_same::value, int>::type = 0> - ValueType value(const typename object_t::key_type& key, ValueType && default_value) const + ValueType value(const typename object_t::key_type& key, const ValueType& default_value) const { // at only works for objects if (JSON_HEDLEY_LIKELY(is_object())) @@ -3797,7 +3797,7 @@ class basic_json return *it; } - return std::move(default_value); + return default_value; } JSON_THROW(type_error::create(306, "cannot use value() with " + std::string(type_name()))); @@ -3809,7 +3809,7 @@ class basic_json */ string_t value(const typename object_t::key_type& key, const char* default_value) const { - return value(key, std::move(string_t(default_value))); + return value(key, string_t(default_value)); } /*! @@ -3857,7 +3857,7 @@ class basic_json */ template::value, int>::type = 0> - ValueType value(const json_pointer& ptr, ValueType && default_value) const + ValueType value(const json_pointer& ptr, const ValueType& default_value) const { // at only works for objects if (JSON_HEDLEY_LIKELY(is_object())) @@ -3869,7 +3869,7 @@ class basic_json } JSON_INTERNAL_CATCH (out_of_range&) { - return std::move(default_value); + return default_value; } } @@ -3883,7 +3883,7 @@ class basic_json JSON_HEDLEY_NON_NULL(3) string_t value(const json_pointer& ptr, const char* default_value) const { - return value(ptr, std::move(string_t(default_value))); + return value(ptr, string_t(default_value)); } /*! diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 87222900..05c3c925 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -19715,7 +19715,7 @@ class basic_json template::value and not std::is_same::value, int>::type = 0> - ValueType value(const typename object_t::key_type& key, ValueType && default_value) const + ValueType value(const typename object_t::key_type& key, const ValueType& default_value) const { // at only works for objects if (JSON_HEDLEY_LIKELY(is_object())) @@ -19727,7 +19727,7 @@ class basic_json return *it; } - return std::move(default_value); + return default_value; } JSON_THROW(type_error::create(306, "cannot use value() with " + std::string(type_name()))); @@ -19739,7 +19739,7 @@ class basic_json */ string_t value(const typename object_t::key_type& key, const char* default_value) const { - return value(key, std::move(string_t(default_value))); + return value(key, string_t(default_value)); } /*! @@ -19787,7 +19787,7 @@ class basic_json */ template::value, int>::type = 0> - ValueType value(const json_pointer& ptr, ValueType && default_value) const + ValueType value(const json_pointer& ptr, const ValueType& default_value) const { // at only works for objects if (JSON_HEDLEY_LIKELY(is_object())) @@ -19799,7 +19799,7 @@ class basic_json } JSON_INTERNAL_CATCH (out_of_range&) { - return std::move(default_value); + return default_value; } } @@ -19813,7 +19813,7 @@ class basic_json JSON_HEDLEY_NON_NULL(3) string_t value(const json_pointer& ptr, const char* default_value) const { - return value(ptr, std::move(string_t(default_value))); + return value(ptr, string_t(default_value)); } /*! diff --git a/test/src/unit-regression.cpp b/test/src/unit-regression.cpp index e5cd0337..3f9d9c26 100644 --- a/test/src/unit-regression.cpp +++ b/test/src/unit-regression.cpp @@ -1945,6 +1945,15 @@ TEST_CASE("regression tests") ) ); } + + SECTION("PR #2181 - regression bug with lvalue") + { + // see https://github.com/nlohmann/json/pull/2181#issuecomment-653326060 + json j{{"x", "test"}}; + std::string defval = "default value"; + auto val = j.value("x", defval); + auto val2 = j.value("y", defval); + } } #if not defined(JSON_NOEXCEPTION) diff --git a/test/src/unit-udt_macro.cpp b/test/src/unit-udt_macro.cpp index a6b66e95..90d5e1cc 100644 --- a/test/src/unit-udt_macro.cpp +++ b/test/src/unit-udt_macro.cpp @@ -60,9 +60,9 @@ class person_with_private_data class person_without_private_data_1 { public: - std::string name = ""; - int age = 0; - json metadata = nullptr; + std::string name = ""; + int age = 0; + json metadata = nullptr; bool operator==(const person_without_private_data_1& rhs) const { @@ -82,9 +82,9 @@ class person_without_private_data_1 class person_without_private_data_2 { public: - std::string name = ""; - int age = 0; - json metadata = nullptr; + std::string name = ""; + int age = 0; + json metadata = nullptr; bool operator==(const person_without_private_data_2& rhs) const { From f774a32d2baccc06d744dd8f794fca53babb7fd8 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Wed, 8 Jul 2020 14:47:22 +0200 Subject: [PATCH 14/18] :white_check_mark: fix test --- test/src/unit-assert_macro.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/src/unit-assert_macro.cpp b/test/src/unit-assert_macro.cpp index 416cda23..06aa0770 100644 --- a/test/src/unit-assert_macro.cpp +++ b/test/src/unit-assert_macro.cpp @@ -43,6 +43,8 @@ static int assert_counter; #include using nlohmann::json; +// the test assumes exceptions to work +#if not defined(JSON_NOEXCEPTION) TEST_CASE("JSON_ASSERT(x)") { SECTION("basic_json(first, second)") @@ -53,8 +55,11 @@ TEST_CASE("JSON_ASSERT(x)") json::iterator it; json j; + // in case assertions do not abort execution, an exception is thrown CHECK_THROWS_WITH_AS(json(it, j.end()), "[json.exception.invalid_iterator.201] iterators are not compatible", json::invalid_iterator); + // check that assertion actually happened CHECK(assert_counter == 1); } } +#endif From c7d18c16259048878ab566c30aea2078a94b58fe Mon Sep 17 00:00:00 2001 From: Palmer Dabbelt Date: Thu, 8 Aug 2019 14:36:27 -0700 Subject: [PATCH 15/18] cmake: Generate and install a pkg-config file. The meson builds install a pkg-config file, but the cmake builds don't. This adds a pkg-config file to the cmake builds that is functionally equivalent to the one generated from meson. --- CMakeLists.txt | 12 +++++++++++- cmake/pkg-config.pc.in | 4 ++++ 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 cmake/pkg-config.pc.in diff --git a/CMakeLists.txt b/CMakeLists.txt index f7ba4fa3..372a7a03 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.1) ## PROJECT ## name and version ## -project(nlohmann_json VERSION 3.8.0 LANGUAGES CXX) +project(nlohmann_json VERSION 3.8.0 DESCRIPTION "JSON for Modern C++" LANGUAGES CXX) ## ## INCLUDE @@ -79,6 +79,12 @@ if (MSVC) ) endif() +# Install a pkg-config file, so other tools can find this. +CONFIGURE_FILE( + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/pkg-config.pc.in" + "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc" +) + ## ## TESTS ## create and configure the unit test target @@ -139,4 +145,8 @@ endif() NAMESPACE ${PROJECT_NAME}:: DESTINATION ${NLOHMANN_JSON_CONFIG_INSTALL_DIR} ) + install( + FILES "${CMAKE_BINARY_DIR}/${PROJECT_NAME}.pc" + DESTINATION lib/pkgconfig + ) endif() diff --git a/cmake/pkg-config.pc.in b/cmake/pkg-config.pc.in new file mode 100644 index 00000000..680f10c2 --- /dev/null +++ b/cmake/pkg-config.pc.in @@ -0,0 +1,4 @@ +Name: ${PROJECT_NAME} +Description: ${PROJECT_DESCRIPTION} +Version: ${PROJECT_VERSION} +Cflags: -I${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR} From 251fce819c64b356d039f1777740ab9c0489d495 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89rico=20Rolim?= Date: Wed, 8 Jul 2020 17:10:51 -0300 Subject: [PATCH 16/18] README: add explanation on how to use pkg-config. --- README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/README.md b/README.md index 3bb92d38..41d3145c 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ - [Integration](#integration) - [CMake](#cmake) - [Package Managers](#package-managers) + - [Pkg-config](#pkg-config) - [Examples](#examples) - [JSON as first-class data type](#json-as-first-class-data-type) - [Serialization / Deserialization](#serialization--deserialization) @@ -230,6 +231,20 @@ Please file issues [here](https://github.com/build2-packaging/nlohmann-json) if If you are using [`wsjcpp`](https://wsjcpp.org), you can use the command `wsjcpp install "https://github.com/nlohmann/json:develop"` to get the latest version. Note you can change the branch ":develop" to an existing tag or another branch. +### Pkg-config + +If you are using bare Makefiles, you can use `pkg-config` to generate the include flags that point to where the library is installed: + +```sh +pkg-config nlohmann_json --cflags +``` + +Users of the Meson build system will also be able to use a system wide library, which will be found by `pkg-config`: + +```meson +json = dependency('nlohmann_json', required: true) +``` + ## Examples Beside the examples below, you may want to check the [documentation](https://nlohmann.github.io/json/) where each function contains a separate code example (e.g., check out [`emplace()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a5338e282d1d02bed389d852dd670d98d.html#a5338e282d1d02bed389d852dd670d98d)). All [example files](https://github.com/nlohmann/json/tree/develop/doc/examples) can be compiled and executed on their own (e.g., file [emplace.cpp](https://github.com/nlohmann/json/blob/develop/doc/examples/emplace.cpp)). From d740622f961a07d73fa2f6e1f61841812c998b1f Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Thu, 9 Jul 2020 13:23:33 +0200 Subject: [PATCH 17/18] :pencil: add documentation for macros --- doc/mkdocs/docs/features/arbitrary_types.md | 37 ++++++++++++++ doc/mkdocs/docs/features/macros.md | 55 +++++++++++++++++++++ doc/mkdocs/docs/home/exceptions.md | 18 +++++++ doc/mkdocs/mkdocs.yml | 1 + 4 files changed, 111 insertions(+) create mode 100644 doc/mkdocs/docs/features/macros.md diff --git a/doc/mkdocs/docs/features/arbitrary_types.md b/doc/mkdocs/docs/features/arbitrary_types.md index 3d238317..7bd7adf7 100644 --- a/doc/mkdocs/docs/features/arbitrary_types.md +++ b/doc/mkdocs/docs/features/arbitrary_types.md @@ -81,6 +81,43 @@ Some important things: * You do not need to add serializers or deserializers for STL types like `std::vector`: the library already implements these. +## Simplify your life with macros + +If you just want to serialize/deserialize some structs, the `to_json`/`from_json` functions can be a lot of boilerplate. + +There are two macros to make your life easier as long as you (1) want to use a JSON object as serialization and (2) want to use the member variable names as object keys in that object: + +- `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(name, member1, member2, ...)` is to be defined inside of the namespace of the class/struct to create code for. +- `NLOHMANN_DEFINE_TYPE_INTRUSIVE(name, member1, member2, ...)` is to be defined inside of the class/struct to create code for. This macro can also access private members. + +In both macros, the first parameter is the name of the class/struct, and all remaining parameters name the members. + +??? example + + The `to_json`/`from_json` functions for the `person` struct above can be created with: + + ```cpp + namespace ns { + NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(person, name, address, age) + } + ``` + + Here is an example with private members, where `NLOHMANN_DEFINE_TYPE_INTRUSIVE` is needed: + + ```cpp + namespace ns { + class address { + private: + std::string street; + int housenumber; + int postcode; + + public: + NLOHMANN_DEFINE_TYPE_INTRUSIVE(address, street, housenumber, postcode) + }; + } + ``` + ## How do I convert third-party types? This requires a bit more advanced technique. But first, let's see how this conversion mechanism works: diff --git a/doc/mkdocs/docs/features/macros.md b/doc/mkdocs/docs/features/macros.md new file mode 100644 index 00000000..7147be7e --- /dev/null +++ b/doc/mkdocs/docs/features/macros.md @@ -0,0 +1,55 @@ +# Supported Macros + +Some aspects of the library can be configured by defining preprocessor macros before including the `json.hpp` header. + +## `JSON_CATCH_USER(exception)` + +This macro overrides `#!cpp catch` calls inside the library. The argument is the type of the exception to catch. As of version 3.8.0, the library only catches `std::out_of_range` exceptions internally to rethrow them as [`json::out_of_range`](../home/exceptions.md#out-of-range) exceptions. The macro is always followed by a scope. + +See [Switch off exceptions](../home/exceptions.md#switch-off-exceptions) for an example. + +## `JSON_NOEXCEPTION` + +Exceptions can be switched off by defining the symbol `JSON_NOEXCEPTION`. +When defining `JSON_NOEXCEPTION`, `#!cpp try` is replaced by `#!cpp if (true)`, +`#!cpp catch` is replaced by `#!cpp if (false)`, and `#!cpp throw` is replaced by `#!cpp std::abort()`. + +The same effect is achieved by setting the compiler flag `-fno-exceptions`. + +## `JSON_SKIP_UNSUPPORTED_COMPILER_CHECK` + +When defined, the library will not create a compile error when a known unsupported compiler is detected. This allows to use the library with compilers that do not fully support C++11 and may only work if unsupported features are not used. + +## `JSON_THROW_USER(exception)` + +This macro overrides `#!cpp throw` calls inside the library. The argument is the exception to be thrown. Note that `JSON_THROW_USER` should leave the current scope (e.g., by throwing or aborting), as continuing after it may yield undefined behavior. + +See [Switch off exceptions](../home/exceptions.md#switch-off-exceptions) for an example. + +## `JSON_TRY_USER` + +This macro overrides `#!cpp try` calls inside the library. It has no arguments and is always followed by a scope. + +See [Switch off exceptions](../home/exceptions.md#switch-off-exceptions) for an example. + +## `NLOHMANN_DEFINE_TYPE_INTRUSIVE(type, member...)` + +This macro can be used to simplify the serialization/deserialization of types if (1) want to use a JSON object as serialization and (2) want to use the member variable names as object keys in that object. + +The macro is to be defined inside of the class/struct to create code for. Unlike [`NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE`](#nlohmann_define_type_non_intrusivetype-member), it can access private members. +The first parameter is the name of the class/struct, and all remaining parameters name the members. + +See [Simplify your life with macros](arbitrary_types.md#simplify-your-life-with-macros) for an example. + +## `NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(type, member...)` + +This macro can be used to simplify the serialization/deserialization of types if (1) want to use a JSON object as serialization and (2) want to use the member variable names as object keys in that object. + +The macro is to be defined inside of the namespace of the class/struct to create code for. Private members cannot be accessed. Use [`NLOHMANN_DEFINE_TYPE_INTRUSIVE`](#nlohmann_define_type_intrusivetype-member) in these scenarios. +The first parameter is the name of the class/struct, and all remaining parameters name the members. + +See [Simplify your life with macros](arbitrary_types.md#simplify-your-life-with-macros) for an example. + +## `NLOHMANN_JSON_SERIALIZE_ENUM(type, ...)` + +This macro simplifies the serialization/deserialization of enum types. See [Specializing enum conversion](enum_conversion.md) for more information. diff --git a/doc/mkdocs/docs/home/exceptions.md b/doc/mkdocs/docs/home/exceptions.md index 92dfb43b..d7430ccc 100644 --- a/doc/mkdocs/docs/home/exceptions.md +++ b/doc/mkdocs/docs/home/exceptions.md @@ -32,6 +32,24 @@ Exceptions are used widely within the library. They can, however, be switched of Note that `JSON_THROW_USER` should leave the current scope (e.g., by throwing or aborting), as continuing after it may yield undefined behavior. +??? example + + The code below switches off exceptions and creates a log entry with a detailed error message in case of errors. + + ```cpp + #include + + #define JSON_TRY_USER if(true) + #define JSON_CATCH_USER(exception) if(false) + #define JSON_THROW_USER(exception) \ + {std::clog << "Error in " << __FILE__ << ":" << __LINE__ \ + << " (function " << __FUNCTION__ << ") - " \ + << (exception).what() << std::endl; \ + std::abort();} + + #include + ``` + ## Parse errors This exception is thrown by the library when a parse error occurs. Parse errors diff --git a/doc/mkdocs/mkdocs.yml b/doc/mkdocs/mkdocs.yml index 5d6e3b4e..9169e4f1 100644 --- a/doc/mkdocs/mkdocs.yml +++ b/doc/mkdocs/mkdocs.yml @@ -49,6 +49,7 @@ nav: - features/json_patch.md - features/merge_patch.md - features/enum_conversion.md + - features/macros.md - Parsing: - features/parsing/index.md - features/parsing/parse_exceptions.md From cbafed349493dd8b072b5c1c5ac7f7c0ef0ed7df Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Fri, 10 Jul 2020 12:53:48 +0200 Subject: [PATCH 18/18] :arrow_down: require CMake 3.1 --- CMakeLists.txt | 2 +- cmake/pkg-config.pc.in | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 372a7a03..5df3f99f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.1) ## PROJECT ## name and version ## -project(nlohmann_json VERSION 3.8.0 DESCRIPTION "JSON for Modern C++" LANGUAGES CXX) +project(nlohmann_json VERSION 3.8.0 LANGUAGES CXX) ## ## INCLUDE diff --git a/cmake/pkg-config.pc.in b/cmake/pkg-config.pc.in index 680f10c2..3541abf0 100644 --- a/cmake/pkg-config.pc.in +++ b/cmake/pkg-config.pc.in @@ -1,4 +1,4 @@ Name: ${PROJECT_NAME} -Description: ${PROJECT_DESCRIPTION} +Description: JSON for Modern C++ Version: ${PROJECT_VERSION} Cflags: -I${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}