diff --git a/doc/examples/basic_json.cpp b/doc/examples/basic_json.cpp deleted file mode 100644 index 0f36e4f8..00000000 --- a/doc/examples/basic_json.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include - -using json = nlohmann::json; - -int main() -{ - // create a JSON value with default null value - json j; - - // serialize the JSON null value - std::cout << j << '\n'; -} diff --git a/doc/examples/basic_json.link b/doc/examples/basic_json.link deleted file mode 100644 index e5c17c93..00000000 --- a/doc/examples/basic_json.link +++ /dev/null @@ -1 +0,0 @@ -online \ No newline at end of file diff --git a/doc/examples/basic_json.output b/doc/examples/basic_json.output deleted file mode 100644 index 19765bd5..00000000 --- a/doc/examples/basic_json.output +++ /dev/null @@ -1 +0,0 @@ -null diff --git a/doc/examples/basic_json__istream.cpp b/doc/examples/basic_json__istream.cpp index 71f16ed3..32885b22 100644 --- a/doc/examples/basic_json__istream.cpp +++ b/doc/examples/basic_json__istream.cpp @@ -27,7 +27,8 @@ int main() ss << text; // create JSON from stream - json j_complete(ss); + json j_complete(ss); // deprecated! + // shall be replaced by: json j_complete = json::parse(ss); std::cout << std::setw(4) << j_complete << "\n\n"; @@ -51,5 +52,6 @@ int main() // create JSON from stream (with callback) json j_filtered(ss, cb); + // shall be replaced by: json j_filtered = json::parse(ss, cb); std::cout << std::setw(4) << j_filtered << '\n'; } \ No newline at end of file diff --git a/doc/examples/basic_json__istream.link b/doc/examples/basic_json__istream.link index 20d1033c..eb165e2f 100644 --- a/doc/examples/basic_json__istream.link +++ b/doc/examples/basic_json__istream.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/basic_json__nullptr_t.cpp b/doc/examples/basic_json__nullptr_t.cpp index 426afabc..d0156d53 100644 --- a/doc/examples/basic_json__nullptr_t.cpp +++ b/doc/examples/basic_json__nullptr_t.cpp @@ -4,9 +4,12 @@ using json = nlohmann::json; int main() { - // create a JSON null value - json j(nullptr); + // implicitly create a JSON null value + json j1; + + // explicitly create a JSON null value + json j2(nullptr); // serialize the JSON null value - std::cout << j << '\n'; + std::cout << j1 << '\n' << j2 << '\n'; } diff --git a/doc/examples/basic_json__nullptr_t.link b/doc/examples/basic_json__nullptr_t.link index 7e917752..f911caa5 100644 --- a/doc/examples/basic_json__nullptr_t.link +++ b/doc/examples/basic_json__nullptr_t.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/basic_json__nullptr_t.output b/doc/examples/basic_json__nullptr_t.output index 19765bd5..c1e4b6c1 100644 --- a/doc/examples/basic_json__nullptr_t.output +++ b/doc/examples/basic_json__nullptr_t.output @@ -1 +1,2 @@ null +null diff --git a/src/json.hpp b/src/json.hpp index 8ac262e6..1a07e46c 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -74,6 +74,15 @@ SOFTWARE. #pragma GCC diagnostic ignored "-Wfloat-equal" #endif +// allow for portable deprecation warnings +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #define JSON_DEPRECATED __attribute__((deprecated)) +#elif defined(_MSC_VER) + #define JSON_DEPRECATED __declspec(deprecated) +#else + #define JSON_DEPRECATED +#endif + /*! @brief namespace for Niels Lohmann @see https://github.com/nlohmann @@ -1058,40 +1067,10 @@ class basic_json } /*! - @brief create a null object (implicitly) + @brief create a null object - Create a `null` JSON value. This is the implicit version of the `null` - value constructor as it takes no parameters. - - @note The class invariant is satisfied, because it poses no requirements - for null values. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this constructor never throws - exceptions. - - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is constant. - - As postcondition, it holds: `basic_json().empty() == true`. - - @liveexample{The following code shows the constructor for a `null` JSON - value.,basic_json} - - @sa @ref basic_json(std::nullptr_t) -- create a `null` value - - @since version 1.0.0 - */ - basic_json() = default; - - /*! - @brief create a null object (explicitly) - - Create a `null` JSON value. This is the explicitly version of the `null` - value constructor as it takes a null pointer as parameter. It allows to - create `null` values by explicitly assigning a `nullptr` to a JSON value. + Create a `null` JSON value. It either takes a null pointer as parameter + (explicitly creating `null`) or no parameter (implicitly creating `null`). The passed null pointer itself is not read -- it is only used to choose the right constructor. @@ -1100,15 +1079,12 @@ class basic_json @exceptionsafety No-throw guarantee: this constructor never throws exceptions. - @liveexample{The following code shows the constructor with null pointer - parameter.,basic_json__nullptr_t} - - @sa @ref basic_json() -- default constructor (implicitly creating a `null` - value) + @liveexample{The following code shows the constructor with and without a + null pointer parameter.,basic_json__nullptr_t} @since version 1.0.0 */ - basic_json(std::nullptr_t) noexcept + basic_json(std::nullptr_t = nullptr) noexcept : basic_json(value_t::null) { assert_invariant(); @@ -1951,12 +1927,21 @@ class basic_json @note A UTF-8 byte order mark is silently ignored. + @deprecated This constructor is deprecated and will be removed in version + 3.0.0 to unify the interface of the library. Deserialization will be + done by stream operators or by calling one of the `parse` functions, + e.g. @ref parse(std::istream&, const parser_callback_t). That is, calls + like `json j(i);` for an input stream @a i need to be replaced by + `json j = json::parse(i);`. See the example below. + @liveexample{The example below demonstrates constructing a JSON value from a `std::stringstream` with and without callback function.,basic_json__istream} - @since version 2.0.0 + @since version 2.0.0, deprecated in version 2.0.3, to be removed in + version 3.0.0 */ + JSON_DEPRECATED explicit basic_json(std::istream& i, const parser_callback_t cb = nullptr) { *this = parser(i, cb).parse(); diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 3b676458..300337a2 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -74,6 +74,15 @@ SOFTWARE. #pragma GCC diagnostic ignored "-Wfloat-equal" #endif +// allow for portable deprecation warnings +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #define JSON_DEPRECATED __attribute__((deprecated)) +#elif defined(_MSC_VER) + #define JSON_DEPRECATED __declspec(deprecated) +#else + #define JSON_DEPRECATED +#endif + /*! @brief namespace for Niels Lohmann @see https://github.com/nlohmann @@ -1058,40 +1067,10 @@ class basic_json } /*! - @brief create a null object (implicitly) + @brief create a null object - Create a `null` JSON value. This is the implicit version of the `null` - value constructor as it takes no parameters. - - @note The class invariant is satisfied, because it poses no requirements - for null values. - - @complexity Constant. - - @exceptionsafety No-throw guarantee: this constructor never throws - exceptions. - - @requirement This function helps `basic_json` satisfying the - [Container](http://en.cppreference.com/w/cpp/concept/Container) - requirements: - - The complexity is constant. - - As postcondition, it holds: `basic_json().empty() == true`. - - @liveexample{The following code shows the constructor for a `null` JSON - value.,basic_json} - - @sa @ref basic_json(std::nullptr_t) -- create a `null` value - - @since version 1.0.0 - */ - basic_json() = default; - - /*! - @brief create a null object (explicitly) - - Create a `null` JSON value. This is the explicitly version of the `null` - value constructor as it takes a null pointer as parameter. It allows to - create `null` values by explicitly assigning a `nullptr` to a JSON value. + Create a `null` JSON value. It either takes a null pointer as parameter + (explicitly creating `null`) or no parameter (implicitly creating `null`). The passed null pointer itself is not read -- it is only used to choose the right constructor. @@ -1100,15 +1079,12 @@ class basic_json @exceptionsafety No-throw guarantee: this constructor never throws exceptions. - @liveexample{The following code shows the constructor with null pointer - parameter.,basic_json__nullptr_t} - - @sa @ref basic_json() -- default constructor (implicitly creating a `null` - value) + @liveexample{The following code shows the constructor with and without a + null pointer parameter.,basic_json__nullptr_t} @since version 1.0.0 */ - basic_json(std::nullptr_t) noexcept + basic_json(std::nullptr_t = nullptr) noexcept : basic_json(value_t::null) { assert_invariant(); @@ -1951,12 +1927,21 @@ class basic_json @note A UTF-8 byte order mark is silently ignored. + @deprecated This constructor is deprecated and will be removed in version + 3.0.0 to unify the interface of the library. Deserialization will be + done by stream operators or by calling one of the `parse` functions, + e.g. @ref parse(std::istream&, const parser_callback_t). That is, calls + like `json j(i);` for an input stream @a i need to be replaced by + `json j = json::parse(i);`. See the example below. + @liveexample{The example below demonstrates constructing a JSON value from a `std::stringstream` with and without callback function.,basic_json__istream} - @since version 2.0.0 + @since version 2.0.0, deprecated in version 2.0.3, to be removed in + version 3.0.0 */ + JSON_DEPRECATED explicit basic_json(std::istream& i, const parser_callback_t cb = nullptr) { *this = parser(i, cb).parse(); diff --git a/test/src/unit-class_const_iterator.cpp b/test/src/unit-class_const_iterator.cpp index 4908b5ce..b64e7e3c 100644 --- a/test/src/unit-class_const_iterator.cpp +++ b/test/src/unit-class_const_iterator.cpp @@ -64,6 +64,22 @@ TEST_CASE("const_iterator class") json::const_iterator it2(&j); it2 = it; } + + SECTION("copy constructor from non-const iterator") + { + SECTION("create from uninitialized iterator") + { + const json::iterator it {}; + json::const_iterator cit(it); + } + + SECTION("create from initialized iterator") + { + json j; + const json::iterator it = j.begin(); + json::const_iterator cit(it); + } + } } SECTION("initialization") diff --git a/test/src/unit-constructor1.cpp b/test/src/unit-constructor1.cpp index 87728648..8a26738b 100644 --- a/test/src/unit-constructor1.cpp +++ b/test/src/unit-constructor1.cpp @@ -709,7 +709,7 @@ TEST_CASE("constructors") SECTION("float") { - float n = 42.23; + float n = 42.23f; json j(n); CHECK(j.type() == json::value_t::number_float); CHECK(j.m_value.number_float == Approx(j_reference.m_value.number_float)); diff --git a/test/src/unit-deserialization.cpp b/test/src/unit-deserialization.cpp index dcd7c272..49ae7b4b 100644 --- a/test/src/unit-deserialization.cpp +++ b/test/src/unit-deserialization.cpp @@ -35,49 +35,95 @@ using nlohmann::json; TEST_CASE("deserialization") { - SECTION("stream") + SECTION("successful deserialization") { - std::stringstream ss; - ss << "[\"foo\",1,2,3,false,{\"one\":1}]"; - json j = json::parse(ss); - CHECK(j == json({"foo", 1, 2, 3, false, {{"one", 1}}})); + SECTION("stream") + { + std::stringstream ss; + ss << "[\"foo\",1,2,3,false,{\"one\":1}]"; + json j = json::parse(ss); + CHECK(j == json({"foo", 1, 2, 3, false, {{"one", 1}}})); + } + + SECTION("string literal") + { + auto s = "[\"foo\",1,2,3,false,{\"one\":1}]"; + json j = json::parse(s); + CHECK(j == json({"foo", 1, 2, 3, false, {{"one", 1}}})); + } + + SECTION("string_t") + { + json::string_t s = "[\"foo\",1,2,3,false,{\"one\":1}]"; + json j = json::parse(s); + CHECK(j == json({"foo", 1, 2, 3, false, {{"one", 1}}})); + } + + SECTION("operator<<") + { + std::stringstream ss; + ss << "[\"foo\",1,2,3,false,{\"one\":1}]"; + json j; + j << ss; + CHECK(j == json({"foo", 1, 2, 3, false, {{"one", 1}}})); + } + + SECTION("operator>>") + { + std::stringstream ss; + ss << "[\"foo\",1,2,3,false,{\"one\":1}]"; + json j; + ss >> j; + CHECK(j == json({"foo", 1, 2, 3, false, {{"one", 1}}})); + } + + SECTION("user-defined string literal") + { + CHECK("[\"foo\",1,2,3,false,{\"one\":1}]"_json == json({"foo", 1, 2, 3, false, {{"one", 1}}})); + } } - SECTION("string literal") + SECTION("unsuccessful deserialization") { - auto s = "[\"foo\",1,2,3,false,{\"one\":1}]"; - json j = json::parse(s); - CHECK(j == json({"foo", 1, 2, 3, false, {{"one", 1}}})); - } + SECTION("stream") + { + std::stringstream ss; + ss << "[\"foo\",1,2,3,false,{\"one\":1}"; + CHECK_THROWS_AS(json::parse(ss), std::invalid_argument); + CHECK_THROWS_WITH(json::parse(ss), "parse error - unexpected end of input"); + } - SECTION("string_t") - { - json::string_t s = "[\"foo\",1,2,3,false,{\"one\":1}]"; - json j = json::parse(s); - CHECK(j == json({"foo", 1, 2, 3, false, {{"one", 1}}})); - } + SECTION("string") + { + json::string_t s = "[\"foo\",1,2,3,false,{\"one\":1}"; + CHECK_THROWS_AS(json::parse(s), std::invalid_argument); + CHECK_THROWS_WITH(json::parse(s), "parse error - unexpected end of input; expected ']'"); + } - SECTION("operator<<") - { - std::stringstream ss; - ss << "[\"foo\",1,2,3,false,{\"one\":1}]"; - json j; - j << ss; - CHECK(j == json({"foo", 1, 2, 3, false, {{"one", 1}}})); - } + SECTION("operator<<") + { + std::stringstream ss; + ss << "[\"foo\",1,2,3,false,{\"one\":1}"; + json j; + CHECK_THROWS_AS(j << ss, std::invalid_argument); + CHECK_THROWS_WITH(j << ss, "parse error - unexpected end of input"); + } - SECTION("operator>>") - { - std::stringstream ss; - ss << "[\"foo\",1,2,3,false,{\"one\":1}]"; - json j; - ss >> j; - CHECK(j == json({"foo", 1, 2, 3, false, {{"one", 1}}})); - } + SECTION("operator>>") + { + std::stringstream ss; + ss << "[\"foo\",1,2,3,false,{\"one\":1}"; + json j; + CHECK_THROWS_AS(ss >> j, std::invalid_argument); + CHECK_THROWS_WITH(ss >> j, "parse error - unexpected end of input"); + } - SECTION("user-defined string literal") - { - CHECK("[\"foo\",1,2,3,false,{\"one\":1}]"_json == json({"foo", 1, 2, 3, false, {{"one", 1}}})); + SECTION("user-defined string literal") + { + CHECK_THROWS_AS("[\"foo\",1,2,3,false,{\"one\":1}"_json, std::invalid_argument); + CHECK_THROWS_WITH("[\"foo\",1,2,3,false,{\"one\":1}"_json, + "parse error - unexpected end of input; expected ']'"); + } } SECTION("contiguous containers")