From c2e80a72d71662b483b21bf1d648eedc43c720d4 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Wed, 29 Mar 2017 00:39:47 +0200 Subject: [PATCH] :hammer: deprecated j << istream / j >> ostream functions #367 The implementation is non-standard. Deprecation allows a simpler API in the future without removing any features. --- Makefile | 3 ++ src/json.hpp | 66 +++++++++++++++++++++++------------- src/json.hpp.re2c | 66 +++++++++++++++++++++++------------- test/src/unit-regression.cpp | 12 ++++--- test/src/unit-testsuites.cpp | 28 +++++++-------- test/src/unit-unicode.cpp | 4 +-- 6 files changed, 110 insertions(+), 69 deletions(-) diff --git a/Makefile b/Makefile index 20857022f..ab403afb4 100644 --- a/Makefile +++ b/Makefile @@ -49,6 +49,7 @@ doctest: # -Wno-documentation-unknown-command: code uses user-defined commands like @complexity # -Wno-exit-time-destructors: warning in Catch code # -Wno-keyword-macro: unit-tests use "#define private public" +# -Wno-deprecated-declarations: the library deprecated some functions # -Wno-weak-vtables: exception class is defined inline, but has virtual method # -Wno-range-loop-analysis: iterator_wrapper tests tests "for(const auto i...)" pedantic_clang: @@ -59,6 +60,7 @@ pedantic_clang: -Wno-documentation-unknown-command \ -Wno-exit-time-destructors \ -Wno-keyword-macro \ + -Wno-deprecated-declarations \ -Wno-weak-vtables \ -Wno-range-loop-analysis" @@ -66,6 +68,7 @@ pedantic_clang: pedantic_gcc: $(MAKE) json_unit CXX=g++ CXXFLAGS="\ -std=c++11 \ + -Wno-deprecated-declarations \ -Werror \ -Wall -Wpedantic -Wextra \ -Walloca \ diff --git a/src/json.hpp b/src/json.hpp index 37db5c45f..3345cf2db 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -78,6 +78,15 @@ SOFTWARE. #pragma GCC diagnostic ignored "-Wdocumentation" #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 + // allow to disable exceptions #if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && not defined(JSON_NOEXCEPTION) #define JSON_THROW(exception) throw exception @@ -217,8 +226,8 @@ class parse_error : public exception const size_t byte; private: - parse_error(int id, size_t byte_, const char* what_arg) - : exception(id, what_arg), byte(byte_) + parse_error(int id_, size_t byte_, const char* what_arg) + : exception(id_, what_arg), byte(byte_) {} }; @@ -256,8 +265,8 @@ class invalid_iterator : public exception } private: - invalid_iterator(int id, const char* what_arg) - : exception(id, what_arg) + invalid_iterator(int id_, const char* what_arg) + : exception(id_, what_arg) {} }; @@ -295,8 +304,8 @@ class type_error : public exception } private: - type_error(int id, const char* what_arg) - : exception(id, what_arg) + type_error(int id_, const char* what_arg) + : exception(id_, what_arg) {} }; @@ -326,8 +335,8 @@ class out_of_range : public exception } private: - out_of_range(int id, const char* what_arg) - : exception(id, what_arg) + out_of_range(int id_, const char* what_arg) + : exception(id_, what_arg) {} }; @@ -352,8 +361,8 @@ class other_error : public exception } private: - other_error(int id, const char* what_arg) - : exception(id, what_arg) + other_error(int id_, const char* what_arg) + : exception(id_, what_arg) {} }; @@ -7083,8 +7092,12 @@ class basic_json /*! @brief serialize to stream - @copydoc operator<<(std::ostream&, const basic_json&) + @deprecated This stream operator is deprecated and will be removed in a + future version of the library. Please use + @ref std::ostream& operator<<(std::ostream&, const basic_json&) + instead; that is, replace calls like `j >> o;` with `o << j;`. */ + JSON_DEPRECATED friend std::ostream& operator>>(const basic_json& j, std::ostream& o) { return o << j; @@ -7357,6 +7370,20 @@ class basic_json return parse(std::begin(c), std::end(c), cb); } + /*! + @brief deserialize from stream + @deprecated This stream operator is deprecated and will be removed in a + future version of the library. Please use + @ref std::istream& operator>>(std::istream&, basic_json&) + instead; that is, replace calls like `j << i;` with `i >> j;`. + */ + JSON_DEPRECATED + friend std::istream& operator<<(basic_json& j, std::istream& i) + { + j = parser(i).parse(); + return i; + } + /*! @brief deserialize from stream @@ -7383,16 +7410,6 @@ class basic_json @since version 1.0.0 */ - friend std::istream& operator<<(basic_json& j, std::istream& i) - { - j = parser(i).parse(); - return i; - } - - /*! - @brief deserialize from stream - @copydoc operator<<(basic_json&, std::istream&) - */ friend std::istream& operator>>(std::istream& i, basic_json& j) { j = parser(i).parse(); @@ -8574,7 +8591,7 @@ class basic_json case 0x7f: // UTF-8 string (indefinite length) { std::string result; - while (check_length(v.size(), 1, idx), v[idx] != 0xff) + while (static_cast(check_length(v.size(), 1, idx)), v[idx] != 0xff) { string_t s = from_cbor_internal(v, idx); result += s; @@ -8670,7 +8687,7 @@ class basic_json case 0x9f: // array (indefinite length) { basic_json result = value_t::array; - while (check_length(v.size(), 1, idx), v[idx] != 0xff) + while (static_cast(check_length(v.size(), 1, idx)), v[idx] != 0xff) { result.push_back(from_cbor_internal(v, idx)); } @@ -8775,7 +8792,7 @@ class basic_json case 0xbf: // map (indefinite length) { basic_json result = value_t::object; - while (check_length(v.size(), 1, idx), v[idx] != 0xff) + while (static_cast(check_length(v.size(), 1, idx)), v[idx] != 0xff) { cbor_expect_string(v, idx); std::string key = from_cbor_internal(v, idx); @@ -13874,5 +13891,6 @@ inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std #undef JSON_CATCH #undef JSON_THROW #undef JSON_TRY +#undef JSON_DEPRECATED #endif diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index cafb20671..60bb63c6d 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -78,6 +78,15 @@ SOFTWARE. #pragma GCC diagnostic ignored "-Wdocumentation" #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 + // allow to disable exceptions #if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && not defined(JSON_NOEXCEPTION) #define JSON_THROW(exception) throw exception @@ -217,8 +226,8 @@ class parse_error : public exception const size_t byte; private: - parse_error(int id, size_t byte_, const char* what_arg) - : exception(id, what_arg), byte(byte_) + parse_error(int id_, size_t byte_, const char* what_arg) + : exception(id_, what_arg), byte(byte_) {} }; @@ -256,8 +265,8 @@ class invalid_iterator : public exception } private: - invalid_iterator(int id, const char* what_arg) - : exception(id, what_arg) + invalid_iterator(int id_, const char* what_arg) + : exception(id_, what_arg) {} }; @@ -295,8 +304,8 @@ class type_error : public exception } private: - type_error(int id, const char* what_arg) - : exception(id, what_arg) + type_error(int id_, const char* what_arg) + : exception(id_, what_arg) {} }; @@ -326,8 +335,8 @@ class out_of_range : public exception } private: - out_of_range(int id, const char* what_arg) - : exception(id, what_arg) + out_of_range(int id_, const char* what_arg) + : exception(id_, what_arg) {} }; @@ -352,8 +361,8 @@ class other_error : public exception } private: - other_error(int id, const char* what_arg) - : exception(id, what_arg) + other_error(int id_, const char* what_arg) + : exception(id_, what_arg) {} }; @@ -7083,8 +7092,12 @@ class basic_json /*! @brief serialize to stream - @copydoc operator<<(std::ostream&, const basic_json&) + @deprecated This stream operator is deprecated and will be removed in a + future version of the library. Please use + @ref std::ostream& operator<<(std::ostream&, const basic_json&) + instead; that is, replace calls like `j >> o;` with `o << j;`. */ + JSON_DEPRECATED friend std::ostream& operator>>(const basic_json& j, std::ostream& o) { return o << j; @@ -7357,6 +7370,20 @@ class basic_json return parse(std::begin(c), std::end(c), cb); } + /*! + @brief deserialize from stream + @deprecated This stream operator is deprecated and will be removed in a + future version of the library. Please use + @ref std::istream& operator>>(std::istream&, basic_json&) + instead; that is, replace calls like `j << i;` with `i >> j;`. + */ + JSON_DEPRECATED + friend std::istream& operator<<(basic_json& j, std::istream& i) + { + j = parser(i).parse(); + return i; + } + /*! @brief deserialize from stream @@ -7383,16 +7410,6 @@ class basic_json @since version 1.0.0 */ - friend std::istream& operator<<(basic_json& j, std::istream& i) - { - j = parser(i).parse(); - return i; - } - - /*! - @brief deserialize from stream - @copydoc operator<<(basic_json&, std::istream&) - */ friend std::istream& operator>>(std::istream& i, basic_json& j) { j = parser(i).parse(); @@ -8574,7 +8591,7 @@ class basic_json case 0x7f: // UTF-8 string (indefinite length) { std::string result; - while (check_length(v.size(), 1, idx), v[idx] != 0xff) + while (static_cast(check_length(v.size(), 1, idx)), v[idx] != 0xff) { string_t s = from_cbor_internal(v, idx); result += s; @@ -8670,7 +8687,7 @@ class basic_json case 0x9f: // array (indefinite length) { basic_json result = value_t::array; - while (check_length(v.size(), 1, idx), v[idx] != 0xff) + while (static_cast(check_length(v.size(), 1, idx)), v[idx] != 0xff) { result.push_back(from_cbor_internal(v, idx)); } @@ -8775,7 +8792,7 @@ class basic_json case 0xbf: // map (indefinite length) { basic_json result = value_t::object; - while (check_length(v.size(), 1, idx), v[idx] != 0xff) + while (static_cast(check_length(v.size(), 1, idx)), v[idx] != 0xff) { cbor_expect_string(v, idx); std::string key = from_cbor_internal(v, idx); @@ -12907,5 +12924,6 @@ inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std #undef JSON_CATCH #undef JSON_THROW #undef JSON_TRY +#undef JSON_DEPRECATED #endif diff --git a/test/src/unit-regression.cpp b/test/src/unit-regression.cpp index a7b6e117a..1e8f5c230 100644 --- a/test/src/unit-regression.cpp +++ b/test/src/unit-regression.cpp @@ -216,6 +216,8 @@ TEST_CASE("regression tests") { json a = {1, 2, 3}; json::reverse_iterator rit = ++a.rbegin(); + CHECK(*rit == json(2)); + CHECK(rit.value() == json(2)); } { json a = {1, 2, 3}; @@ -540,7 +542,7 @@ TEST_CASE("regression tests") CAPTURE(filename); json j; std::ifstream f(filename); - CHECK_NOTHROW(j << f); + CHECK_NOTHROW(f >> j); } } @@ -556,7 +558,7 @@ TEST_CASE("regression tests") CAPTURE(filename); json j; std::ifstream f(filename); - CHECK_NOTHROW(j << f); + CHECK_NOTHROW(f >> j); } } @@ -586,14 +588,14 @@ TEST_CASE("regression tests") std::stringstream ss; json j; ss << "123"; - CHECK_NOTHROW(j << ss); + CHECK_NOTHROW(ss >> j); // see https://github.com/nlohmann/json/issues/367#issuecomment-262841893: // ss is not at EOF; this yielded an error before the fix // (threw basic_string::append). No, it should just throw // a parse error because of the EOF. - CHECK_THROWS_AS(j << ss, json::parse_error); - CHECK_THROWS_WITH(j << ss, + CHECK_THROWS_AS(ss >> j, json::parse_error); + CHECK_THROWS_WITH(ss >> j, "[json.exception.parse_error.101] parse error at 1: parse error - unexpected end of input"); } diff --git a/test/src/unit-testsuites.cpp b/test/src/unit-testsuites.cpp index 8d6a81622..a4aa1956c 100644 --- a/test/src/unit-testsuites.cpp +++ b/test/src/unit-testsuites.cpp @@ -79,7 +79,7 @@ TEST_CASE("compliance tests from json.org") CAPTURE(filename); json j; std::ifstream f(filename); - CHECK_THROWS_AS(j << f, json::parse_error); + CHECK_THROWS_AS(f >> j, json::parse_error); } } @@ -95,7 +95,7 @@ TEST_CASE("compliance tests from json.org") CAPTURE(filename); json j; std::ifstream f(filename); - CHECK_NOTHROW(j << f); + CHECK_NOTHROW(f >> j); } } } @@ -319,7 +319,7 @@ TEST_CASE("test suite from json-test-suite") // strings in a JSON array std::ifstream f("test/data/json_testsuite/sample.json"); json j; - CHECK_NOTHROW(j << f); + CHECK_NOTHROW(f >> j); // the array has 3 elements CHECK(j.size() == 3); @@ -334,35 +334,35 @@ TEST_CASE("json.org examples") { std::ifstream f("test/data/json.org/1.json"); json j; - CHECK_NOTHROW(j << f); + CHECK_NOTHROW(f >> j); } SECTION("2.json") { std::ifstream f("test/data/json.org/2.json"); json j; - CHECK_NOTHROW(j << f); + CHECK_NOTHROW(f >> j); } SECTION("3.json") { std::ifstream f("test/data/json.org/3.json"); json j; - CHECK_NOTHROW(j << f); + CHECK_NOTHROW(f >> j); } SECTION("4.json") { std::ifstream f("test/data/json.org/4.json"); json j; - CHECK_NOTHROW(j << f); + CHECK_NOTHROW(f >> j); } SECTION("5.json") { std::ifstream f("test/data/json.org/5.json"); json j; - CHECK_NOTHROW(j << f); + CHECK_NOTHROW(f >> j); } } @@ -545,7 +545,7 @@ TEST_CASE("nst's JSONTestSuite") CAPTURE(filename); std::ifstream f(filename); json j; - CHECK_NOTHROW(j << f); + CHECK_NOTHROW(f >> j); } } @@ -754,7 +754,7 @@ TEST_CASE("nst's JSONTestSuite") CAPTURE(filename); std::ifstream f(filename); json j; - CHECK_THROWS_AS(j << f, json::parse_error); + CHECK_THROWS_AS(f >> j, json::parse_error); } } @@ -777,7 +777,7 @@ TEST_CASE("nst's JSONTestSuite") CAPTURE(filename); std::ifstream f(filename); json j; - CHECK_NOTHROW(j << f); + CHECK_NOTHROW(f >> j); } } @@ -797,7 +797,7 @@ TEST_CASE("nst's JSONTestSuite") CAPTURE(filename); std::ifstream f(filename); json j; - CHECK_THROWS_AS(j << f, json::out_of_range); + CHECK_THROWS_AS(f >> j, json::out_of_range); } } @@ -824,7 +824,7 @@ TEST_CASE("nst's JSONTestSuite") CAPTURE(filename); std::ifstream f(filename); json j; - CHECK_THROWS_AS(j << f, json::parse_error); + CHECK_THROWS_AS(f >> j, json::parse_error); } } } @@ -851,7 +851,7 @@ TEST_CASE("Big List of Naughty Strings") { std::ifstream f("test/data/big-list-of-naughty-strings/blns.json"); json j; - CHECK_NOTHROW(j << f); + CHECK_NOTHROW(f >> j); } // check if parsed strings roundtrip diff --git a/test/src/unit-unicode.cpp b/test/src/unit-unicode.cpp index f7cf0ada3..82324ca08 100644 --- a/test/src/unit-unicode.cpp +++ b/test/src/unit-unicode.cpp @@ -125,7 +125,7 @@ TEST_CASE("Unicode", "[hide]") // strings in a JSON array std::ifstream f("test/data/json_nlohmann_tests/all_unicode.json"); json j; - CHECK_NOTHROW(j << f); + CHECK_NOTHROW(f >> j); // the array has 1112064 + 1 elemnts (a terminating "null" value) // Note: 1112064 = 0x1FFFFF code points - 2048 invalid values between @@ -168,7 +168,7 @@ TEST_CASE("Unicode", "[hide]") // read a file with a UTF-8 BOM std::ifstream f("test/data/json_nlohmann_tests/bom.json"); json j; - CHECK_NOTHROW(j << f); + CHECK_NOTHROW(f >> j); } SECTION("error for incomplete/wrong BOM")