From 99b7c7c8efcf7e96ddee9b199fec190107a979ee Mon Sep 17 00:00:00 2001 From: Chris Harris Date: Thu, 20 Sep 2018 11:19:33 -0400 Subject: [PATCH 1/2] Patch nlohmann/json for GCC 4.8 See https://github.com/nlohmann/json/pull/212 for details --- include/nlohmann/detail/macro_scope.hpp | 2 +- include/nlohmann/json.hpp | 36 +++++++++++++---------- single_include/nlohmann/json.hpp | 38 ++++++++++++++----------- 3 files changed, 44 insertions(+), 32 deletions(-) diff --git a/include/nlohmann/detail/macro_scope.hpp b/include/nlohmann/detail/macro_scope.hpp index 80fbece7ed..06805b1a7b 100644 --- a/include/nlohmann/detail/macro_scope.hpp +++ b/include/nlohmann/detail/macro_scope.hpp @@ -10,7 +10,7 @@ #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" #endif #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) - #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900 + #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800 #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" #endif #endif diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index 598aa06b06..35798c8936 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -4943,6 +4943,23 @@ class basic_json return {it, res.second}; } + /// helper for insertion of an iterator (supports GCC 4.8+) + template + iterator insert_iterator(const_iterator pos, Args&& ... args) + { + iterator result(this); + assert(m_value.array != nullptr); + + auto insert_pos = std::distance(m_value.array->begin(), pos.m_it.array_iterator); + m_value.array->insert(pos.m_it.array_iterator, std::forward(args)...); + result.m_it.array_iterator = m_value.array->begin() + insert_pos; + + // For GCC 4.9+ only, this could become: + // result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val); + + return result; + } + /*! @brief inserts element @@ -4977,9 +4994,7 @@ class basic_json } // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, val); - return result; + return insert_iterator(pos, val); } JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); @@ -5030,9 +5045,7 @@ class basic_json } // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val); - return result; + return insert_iterator(pos, cnt, val); } JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); @@ -5094,12 +5107,7 @@ class basic_json } // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert( - pos.m_it.array_iterator, - first.m_it.array_iterator, - last.m_it.array_iterator); - return result; + return insert_iterator(pos, first.m_it.array_iterator, last.m_it.array_iterator); } /*! @@ -5141,9 +5149,7 @@ class basic_json } // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, ilist.begin(), ilist.end()); - return result; + return insert_iterator(pos, ilist.begin(), ilist.end()); } /*! diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 46cf8b18d7..ad053dcfa6 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -125,7 +125,7 @@ using json = basic_json<>; #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" #endif #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) - #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900 + #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800 #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" #endif #endif @@ -16016,6 +16016,23 @@ class basic_json return {it, res.second}; } + /// helper for insertion of an iterator (supports GCC 4.8+) + template + iterator insert_iterator(const_iterator pos, Args&& ... args) + { + iterator result(this); + assert(m_value.array != nullptr); + + auto insert_pos = std::distance(m_value.array->begin(), pos.m_it.array_iterator); + m_value.array->insert(pos.m_it.array_iterator, std::forward(args)...); + result.m_it.array_iterator = m_value.array->begin() + insert_pos; + + // For GCC 4.9+ only, this could become: + // result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val); + + return result; + } + /*! @brief inserts element @@ -16050,9 +16067,7 @@ class basic_json } // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, val); - return result; + return insert_iterator(pos, val); } JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); @@ -16103,9 +16118,7 @@ class basic_json } // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val); - return result; + return insert_iterator(pos, cnt, val); } JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()))); @@ -16167,12 +16180,7 @@ class basic_json } // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert( - pos.m_it.array_iterator, - first.m_it.array_iterator, - last.m_it.array_iterator); - return result; + return insert_iterator(pos, first.m_it.array_iterator, last.m_it.array_iterator); } /*! @@ -16214,9 +16222,7 @@ class basic_json } // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, ilist.begin(), ilist.end()); - return result; + return insert_iterator(pos, ilist.begin(), ilist.end()); } /*! From 7a37ba0c02311b32f5550f2070e8f84b8497ac24 Mon Sep 17 00:00:00 2001 From: Henry Fredrick Schreiner Date: Tue, 25 Sep 2018 18:15:29 +0200 Subject: [PATCH 2/2] Adding 4.8 test to travis --- .github/CONTRIBUTING.md | 2 +- .github/PULL_REQUEST_TEMPLATE.md | 2 +- .travis.yml | 10 +++++++++- README.md | 5 +++-- include/nlohmann/json.hpp | 7 +++++-- single_include/nlohmann/json.hpp | 7 +++++-- test/src/unit-json_patch.cpp | 5 +++-- test/src/unit-regression.cpp | 28 +++++++++++++++++----------- test/src/unit-testsuites.cpp | 11 +++++++---- 9 files changed, 51 insertions(+), 26 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 8dbacb78a1..4ae0cb2d7f 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -54,7 +54,7 @@ To make changes, you need to edit the following files: ## Please don't -- The C++11 support varies between different **compilers** and versions. Please note the [list of supported compilers](https://github.com/nlohmann/json/blob/master/README.md#supported-compilers). Some compilers like GCC 4.8 (and earlier), Clang 3.3 (and earlier), or Microsoft Visual Studio 13.0 and earlier are known not to work due to missing or incomplete C++11 support. Please refrain from proposing changes that work around these compiler's limitations with `#ifdef`s or other means. +- The C++11 support varies between different **compilers** and versions. Please note the [list of supported compilers](https://github.com/nlohmann/json/blob/master/README.md#supported-compilers). Some compilers like GCC 4.7 (and earlier), Clang 3.3 (and earlier), or Microsoft Visual Studio 13.0 and earlier are known not to work due to missing or incomplete C++11 support. Please refrain from proposing changes that work around these compiler's limitations with `#ifdef`s or other means. - Specifically, I am aware of compilation problems with **Microsoft Visual Studio** (there even is an [issue label](https://github.com/nlohmann/json/issues?utf8=✓&q=label%3A%22visual+studio%22+) for these kind of bugs). I understand that even in 2016, complete C++11 support isn't there yet. But please also understand that I do not want to drop features or uglify the code just to make Microsoft's sub-standard compiler happy. The past has shown that there are ways to express the functionality such that the code compiles with the most recent MSVC - unfortunately, this is not the main objective of the project. - Please refrain from proposing changes that would **break [JSON](http://json.org) conformance**. If you propose a conformant extension of JSON to be supported by the library, please motivate this extension. - We shall not extend the library to **support comments**. There is quite some [controversy](https://www.reddit.com/r/programming/comments/4v6chu/why_json_doesnt_support_comments_douglas_crockford/) around this topic, and there were quite some [issues](https://github.com/nlohmann/json/issues/376) on this. We believe that JSON is fine without comments. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index d75a67b4d4..f2c3af6a89 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -13,7 +13,7 @@ Read the [Contribution Guidelines](https://github.com/nlohmann/json/blob/develop ## Please don't -- The C++11 support varies between different **compilers** and versions. Please note the [list of supported compilers](https://github.com/nlohmann/json/blob/master/README.md#supported-compilers). Some compilers like GCC 4.8 (and earlier), Clang 3.3 (and earlier), or Microsoft Visual Studio 13.0 and earlier are known not to work due to missing or incomplete C++11 support. Please refrain from proposing changes that work around these compiler's limitations with `#ifdef`s or other means. +- The C++11 support varies between different **compilers** and versions. Please note the [list of supported compilers](https://github.com/nlohmann/json/blob/master/README.md#supported-compilers). Some compilers like GCC 4.7 (and earlier), Clang 3.3 (and earlier), or Microsoft Visual Studio 13.0 and earlier are known not to work due to missing or incomplete C++11 support. Please refrain from proposing changes that work around these compiler's limitations with `#ifdef`s or other means. - Specifically, I am aware of compilation problems with **Microsoft Visual Studio** (there even is an [issue label](https://github.com/nlohmann/json/issues?utf8=✓&q=label%3A%22visual+studio%22+) for these kind of bugs). I understand that even in 2016, complete C++11 support isn't there yet. But please also understand that I do not want to drop features or uglify the code just to make Microsoft's sub-standard compiler happy. The past has shown that there are ways to express the functionality such that the code compiles with the most recent MSVC - unfortunately, this is not the main objective of the project. - Please refrain from proposing changes that would **break [JSON](http://json.org) conformance**. If you propose a conformant extension of JSON to be supported by the library, please motivate this extension. - Please do not open pull requests that address **multiple issues**. diff --git a/.travis.yml b/.travis.yml index 91903e6401..4c53951010 100644 --- a/.travis.yml +++ b/.travis.yml @@ -168,7 +168,15 @@ matrix: - os: linux compiler: gcc - env: COMPILER=g++-4.9 + env: compiler=g++-4.8 + addons: + apt: + sources: ['ubuntu-toolchain-r-test'] + packages: ['g++-4.8', 'ninja-build'] + + - os: linux + compiler: gcc + env: compiler=g++-4.9 addons: apt: sources: ['ubuntu-toolchain-r-test'] diff --git a/README.md b/README.md index ebaa961b85..3dd04aed55 100644 --- a/README.md +++ b/README.md @@ -843,7 +843,7 @@ json j_from_ubjson = json::from_ubjson(v_ubjson); Though it's 2018 already, the support for C++11 is still a bit sparse. Currently, the following compilers are known to work: -- GCC 4.9 - 8.2 (and possibly later) +- GCC 4.8 - 8.2 (and possibly later) - Clang 3.4 - 6.1 (and possibly later) - Intel C++ Compiler 17.0.2 (and possibly later) - Microsoft Visual C++ 2015 / Build Tools 14.0.25123.0 (and possibly later) @@ -853,7 +853,7 @@ I would be happy to learn about other compilers/versions. Please note: -- GCC 4.8 does not work because of two bugs ([55817](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55817) and [57824](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57824)) in the C++11 support. Note there is a [pull request](https://github.com/nlohmann/json/pull/212) to fix some of the issues. +- GCC 4.8 has a bug [57824](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57824)): multiline raw strings cannot be the arguments to macros. Don't use multiline raw strings directly in macros with this compiler. - Android defaults to using very old compilers and C++ libraries. To fix this, add the following to your `Application.mk`. This will switch to the LLVM C++ library, the Clang compiler, and enable C++11 and other features disabled by default. ``` @@ -872,6 +872,7 @@ The following compilers are currently used in continuous integration at [Travis] | Compiler | Operating System | Version String | |-----------------|------------------------------|----------------| +| GCC 4.8.5 | Ubuntu 14.04.5 LTS | g++-4.8 (Ubuntu 4.8.5-2ubuntu1~14.04.2) 4.8.5 | | GCC 4.9.4 | Ubuntu 14.04.1 LTS | g++-4.9 (Ubuntu 4.9.4-2ubuntu1~14.04.1) 4.9.4 | | GCC 5.5.0 | Ubuntu 14.04.1 LTS | g++-5 (Ubuntu 5.5.0-12ubuntu1~14.04) 5.5.0 20171010 | | GCC 6.4.0 | Ubuntu 14.04.1 LTS | g++-6 (Ubuntu 6.4.0-17ubuntu1~14.04) 6.4.0 20180424 | diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index 35798c8936..3fc3e865d8 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -4943,7 +4943,9 @@ class basic_json return {it, res.second}; } - /// helper for insertion of an iterator (supports GCC 4.8+) + /// Helper for insertion of an iterator + /// @note: This uses std::distance to support GCC 4.8, + /// see https://github.com/nlohmann/json/pull/1257 template iterator insert_iterator(const_iterator pos, Args&& ... args) { @@ -4954,8 +4956,9 @@ class basic_json m_value.array->insert(pos.m_it.array_iterator, std::forward(args)...); result.m_it.array_iterator = m_value.array->begin() + insert_pos; - // For GCC 4.9+ only, this could become: + // This could have been written as: // result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val); + // but the return value of insert is missing in GCC 4.8, so it is written this way instead. return result; } diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index ad053dcfa6..93bb4f231c 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -16016,7 +16016,9 @@ class basic_json return {it, res.second}; } - /// helper for insertion of an iterator (supports GCC 4.8+) + /// Helper for insertion of an iterator + /// @note: This uses std::distance to support GCC 4.8, + /// see https://github.com/nlohmann/json/pull/1257 template iterator insert_iterator(const_iterator pos, Args&& ... args) { @@ -16027,8 +16029,9 @@ class basic_json m_value.array->insert(pos.m_it.array_iterator, std::forward(args)...); result.m_it.array_iterator = m_value.array->begin() + insert_pos; - // For GCC 4.9+ only, this could become: + // This could have been written as: // result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val); + // but the return value of insert is missing in GCC 4.8, so it is written this way instead. return result; } diff --git a/test/src/unit-json_patch.cpp b/test/src/unit-json_patch.cpp index c7c62fe53c..fc8c21e98d 100644 --- a/test/src/unit-json_patch.cpp +++ b/test/src/unit-json_patch.cpp @@ -63,7 +63,7 @@ TEST_CASE("JSON patch") // is not an error, because "a" exists, and "b" will be added to // its value. CHECK_NOTHROW(doc1.patch(patch)); - CHECK(doc1.patch(patch) == R"( + auto doc1_ans = R"( { "a": { "foo": 1, @@ -72,7 +72,8 @@ TEST_CASE("JSON patch") } } } - )"_json); + )"_json; + CHECK(doc1.patch(patch) == doc1_ans); // It is an error in this document: json doc2 = R"({ "q": { "bar": 2 } })"_json; diff --git a/test/src/unit-regression.cpp b/test/src/unit-regression.cpp index 69c0cf29a4..c547864399 100644 --- a/test/src/unit-regression.cpp +++ b/test/src/unit-regression.cpp @@ -1427,20 +1427,26 @@ TEST_CASE("regression tests") } })"_json; - CHECK_THROWS_AS(model.patch(R"([{"op": "move", - "from": "/one/two/three", - "path": "/a/b/c"}])"_json), json::out_of_range&); - CHECK_THROWS_WITH(model.patch(R"([{"op": "move", - "from": "/one/two/three", - "path": "/a/b/c"}])"_json), + auto p1 = R"([{"op": "move", + "from": "/one/two/three", + "path": "/a/b/c"}])"_json; + CHECK_THROWS_AS(model.patch(p1), json::out_of_range&); + + auto p2 = R"([{"op": "move", + "from": "/one/two/three", + "path": "/a/b/c"}])"_json; + CHECK_THROWS_WITH(model.patch(p2), "[json.exception.out_of_range.403] key 'a' not found"); - CHECK_THROWS_AS(model.patch(R"([{"op": "copy", - "from": "/one/two/three", - "path": "/a/b/c"}])"_json), json::out_of_range&); - CHECK_THROWS_WITH(model.patch(R"([{"op": "copy", + auto p3 = R"([{"op": "copy", + "from": "/one/two/three", + "path": "/a/b/c"}])"_json; + CHECK_THROWS_AS(model.patch(p3), json::out_of_range&); + + auto p4 = R"([{"op": "copy", "from": "/one/two/three", - "path": "/a/b/c"}])"_json), + "path": "/a/b/c"}])"_json; + CHECK_THROWS_WITH(model.patch(p4), "[json.exception.out_of_range.403] key 'a' not found"); } diff --git a/test/src/unit-testsuites.cpp b/test/src/unit-testsuites.cpp index 237eb34ee6..908901ab31 100644 --- a/test/src/unit-testsuites.cpp +++ b/test/src/unit-testsuites.cpp @@ -405,7 +405,7 @@ TEST_CASE("RFC 7159 examples") SECTION("13 Examples") { { - CHECK_NOTHROW(json(R"( + auto json_contents = R"( { "Image": { "Width": 800, @@ -420,11 +420,13 @@ TEST_CASE("RFC 7159 examples") "IDs": [116, 943, 234, 38793] } } - )")); + )"; + + CHECK_NOTHROW(json(json_contents)); } { - CHECK_NOTHROW(json(R"( + auto json_contents = R"( [ { "precision": "zip", @@ -446,7 +448,8 @@ TEST_CASE("RFC 7159 examples") "Zip": "94085", "Country": "US" } - ])")); + ])"; + CHECK_NOTHROW(json(json_contents)); } CHECK(json::parse("\"Hello world!\"") == json("Hello world!"));