From 6d3115924c59a0281f1024f1edf2ab5352112825 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Wed, 29 Dec 2021 09:47:05 +0100 Subject: [PATCH] Add C++17 copies of the test binaries (#3101) * :alembic: add C++17 copies of the test binaries * :alembic: use proper header for filesystem * :rotating_light: fix warnings * :alembic: do not use too old compilers with C++17 * :white_check_mark: add test * :hammer: add more constraints #3097 * :alembic: use fix from https://github.com/nlohmann/json/pull/3101#issuecomment-998788786 * :alembic: use fix from https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90050 * :construction_worker: use published CI image --- .clang-tidy | 4 +- .github/workflows/ubuntu.yml | 14 +- cmake/ci.cmake | 8 + doc/mkdocs/docs/features/macros.md | 7 + .../nlohmann/byte_container_with_subtype.hpp | 2 +- .../nlohmann/detail/conversions/from_json.hpp | 18 +- .../nlohmann/detail/conversions/to_json.hpp | 18 +- .../nlohmann/detail/input/binary_reader.hpp | 24 +-- include/nlohmann/detail/input/json_sax.hpp | 12 +- include/nlohmann/detail/input/lexer.hpp | 8 +- include/nlohmann/detail/input/parser.hpp | 4 +- include/nlohmann/detail/macro_scope.hpp | 60 ++++++ include/nlohmann/detail/macro_unscope.hpp | 2 + include/nlohmann/detail/meta/cpp_future.hpp | 2 +- .../nlohmann/detail/output/binary_writer.hpp | 6 +- include/nlohmann/detail/output/serializer.hpp | 10 +- include/nlohmann/json.hpp | 12 +- single_include/nlohmann/json.hpp | 178 +++++++++++++----- test/CMakeLists.txt | 51 +++++ test/src/unit-byte_container_with_subtype.cpp | 6 +- test/src/unit-cbor.cpp | 2 +- test/src/unit-class_parser.cpp | 4 +- test/src/unit-deserialization.cpp | 8 +- test/src/unit-hash.cpp | 4 +- test/src/unit-msgpack.cpp | 2 +- test/src/unit-regression1.cpp | 14 +- test/src/unit-regression2.cpp | 100 ++++++++-- 27 files changed, 442 insertions(+), 138 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index b526aa82fa..30886d7c8e 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -34,9 +34,11 @@ Checks: '*, -llvmlibc-*, -misc-no-recursion, -misc-non-private-member-variables-in-classes, + -modernize-concat-nested-namespaces, + -modernize-use-nodiscard, -modernize-use-trailing-return-type, - -readability-function-size, -readability-function-cognitive-complexity, + -readability-function-size, -readability-identifier-length, -readability-magic-numbers, -readability-redundant-access-specifiers, diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 13253af057..756e82f55a 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -11,7 +11,7 @@ on: jobs: ci_test_clang: runs-on: ubuntu-latest - container: ghcr.io/nlohmann/json-ci:v2.0.0 + container: ghcr.io/nlohmann/json-ci:v2.1.0 steps: - uses: actions/checkout@v2 - name: cmake @@ -21,7 +21,7 @@ jobs: ci_test_gcc: runs-on: ubuntu-latest - container: ghcr.io/nlohmann/json-ci:v2.0.0 + container: ghcr.io/nlohmann/json-ci:v2.1.0 steps: - uses: actions/checkout@v2 - name: cmake @@ -31,7 +31,7 @@ jobs: ci_static_analysis: runs-on: ubuntu-latest - container: ghcr.io/nlohmann/json-ci:v2.0.0 + container: ghcr.io/nlohmann/json-ci:v2.1.0 strategy: matrix: target: [ci_clang_tidy, ci_cppcheck, ci_test_valgrind, ci_test_clang_sanitizer, ci_test_amalgamation, ci_clang_analyze, ci_cpplint, ci_cmake_flags, ci_single_binaries, ci_reproducible_tests, ci_non_git_tests, ci_offline_testdata, ci_infer] @@ -44,7 +44,7 @@ jobs: ci_cmake_options: runs-on: ubuntu-latest - container: ghcr.io/nlohmann/json-ci:v2.0.0 + container: ghcr.io/nlohmann/json-ci:v2.1.0 strategy: matrix: target: [ci_test_diagnostics, ci_test_noexceptions, ci_test_noimplicitconversions] @@ -57,7 +57,7 @@ jobs: ci_test_coverage: runs-on: ubuntu-latest - container: ghcr.io/nlohmann/json-ci:v2.0.0 + container: ghcr.io/nlohmann/json-ci:v2.1.0 steps: - uses: actions/checkout@v2 - name: cmake @@ -77,7 +77,7 @@ jobs: ci_test_compilers: runs-on: ubuntu-latest - container: ghcr.io/nlohmann/json-ci:v2.0.0 + container: ghcr.io/nlohmann/json-ci:v2.1.0 strategy: matrix: compiler: [g++-4.8, g++-4.9, g++-5, g++-6, g++-7, g++-8, g++-9, g++-10, clang++-3.5, clang++-3.6, clang++-3.7, clang++-3.8, clang++-3.9, clang++-4.0, clang++-5.0, clang++-6.0, clang++-7, clang++-8, clang++-9, clang++-10, clang++-11, clang++-12, clang++-13] @@ -90,7 +90,7 @@ jobs: ci_test_standards: runs-on: ubuntu-latest - container: ghcr.io/nlohmann/json-ci:v2.0.0 + container: ghcr.io/nlohmann/json-ci:v2.1.0 strategy: matrix: standard: [11, 14, 17, 20] diff --git a/cmake/ci.cmake b/cmake/ci.cmake index ce8d2299c0..acb797c5b7 100644 --- a/cmake/ci.cmake +++ b/cmake/ci.cmake @@ -814,11 +814,19 @@ add_custom_target(ci_cmake_flags foreach(COMPILER g++-4.8 g++-4.9 g++-5 g++-6 g++-7 g++-8 g++-9 g++-10 clang++-3.5 clang++-3.6 clang++-3.7 clang++-3.8 clang++-3.9 clang++-4.0 clang++-5.0 clang++-6.0 clang++-7 clang++-8 clang++-9 clang++-10 clang++-11 clang++-12 clang++-13) find_program(COMPILER_TOOL NAMES ${COMPILER}) if (COMPILER_TOOL) + if ("${COMPILER}" STREQUAL "clang++-9") + # fix for https://github.com/nlohmann/json/pull/3101#issuecomment-998788786 / https://stackoverflow.com/a/64051725/266378 + set(ADDITIONAL_FLAGS "-DCMAKE_CXX_FLAGS=--gcc-toolchain=/root/gcc/9") + else() + unset(ADDITIONAL_FLAGS) + endif() + add_custom_target(ci_test_compiler_${COMPILER} COMMAND CXX=${COMPILER} ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Debug -GNinja -DJSON_BuildTests=ON -DJSON_FastTests=ON -S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_compiler_${COMPILER} + ${ADDITIONAL_FLAGS} COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_compiler_${COMPILER} COMMAND cd ${PROJECT_BINARY_DIR}/build_compiler_${COMPILER} && ${CMAKE_CTEST_COMMAND} --parallel ${N} --exclude-regex "test-unicode" --output-on-failure COMMENT "Compile and test with ${COMPILER}" diff --git a/doc/mkdocs/docs/features/macros.md b/doc/mkdocs/docs/features/macros.md index 8b10ef1f35..bf279a139d 100644 --- a/doc/mkdocs/docs/features/macros.md +++ b/doc/mkdocs/docs/features/macros.md @@ -24,6 +24,13 @@ The diagnostics messages can also be controlled with the CMake option `JSON_Diag The library targets C++11, but also supports some features introduced in later C++ versions (e.g., `std::string_view` support for C++17). For these new features, the library implements some preprocessor checks to determine the C++ standard. By defining any of these symbols, the internal check is overridden and the provided C++ version is unconditionally assumed. This can be helpful for compilers that only implement parts of the standard and would be detected incorrectly. +## `JSON_HAS_FILESYSTEM`, `JSON_HAS_EXPERIMENTAL_FILESYSTEM` + +When compiling with C++17, the library provides conversions from and to `std::filesystem::path`. As compiler support +for filesystem is limited, the library tries to detect whether ``/`std::filesystem` (`JSON_HAS_FILESYSTEM`) +or ``/`std::experimental::filesystem` (`JSON_HAS_EXPERIMENTAL_FILESYSTEM`) should be used. +To override the built-in check, define `JSON_HAS_FILESYSTEM` or `JSON_HAS_EXPERIMENTAL_FILESYSTEM` to `1`. + ## `JSON_NOEXCEPTION` Exceptions can be switched off by defining the symbol `JSON_NOEXCEPTION`. diff --git a/include/nlohmann/byte_container_with_subtype.hpp b/include/nlohmann/byte_container_with_subtype.hpp index 4086e0834d..474508f317 100644 --- a/include/nlohmann/byte_container_with_subtype.hpp +++ b/include/nlohmann/byte_container_with_subtype.hpp @@ -112,7 +112,7 @@ class byte_container_with_subtype : public BinaryType */ constexpr subtype_type subtype() const noexcept { - return m_has_subtype ? m_subtype : subtype_type(-1); + return m_has_subtype ? m_subtype : static_cast(-1); } /*! diff --git a/include/nlohmann/detail/conversions/from_json.hpp b/include/nlohmann/detail/conversions/from_json.hpp index 71e32aaf71..207d3e3024 100644 --- a/include/nlohmann/detail/conversions/from_json.hpp +++ b/include/nlohmann/detail/conversions/from_json.hpp @@ -19,8 +19,18 @@ #include #include -#ifdef JSON_HAS_CPP_17 - #include +#if JSON_HAS_EXPERIMENTAL_FILESYSTEM +#include +namespace nlohmann::detail +{ +namespace std_fs = std::experimental::filesystem; +} // namespace nlohmann::detail +#elif JSON_HAS_FILESYSTEM +#include +namespace nlohmann::detail +{ +namespace std_fs = std::filesystem; +} // namespace nlohmann::detail #endif namespace nlohmann @@ -448,9 +458,9 @@ void from_json(const BasicJsonType& j, std::unordered_map -void from_json(const BasicJsonType& j, std::filesystem::path& p) +void from_json(const BasicJsonType& j, std_fs::path& p) { if (JSON_HEDLEY_UNLIKELY(!j.is_string())) { diff --git a/include/nlohmann/detail/conversions/to_json.hpp b/include/nlohmann/detail/conversions/to_json.hpp index 79fdb3233f..7628ae0116 100644 --- a/include/nlohmann/detail/conversions/to_json.hpp +++ b/include/nlohmann/detail/conversions/to_json.hpp @@ -15,8 +15,18 @@ #include #include -#ifdef JSON_HAS_CPP_17 - #include +#if JSON_HAS_EXPERIMENTAL_FILESYSTEM +#include +namespace nlohmann::detail +{ +namespace std_fs = std::experimental::filesystem; +} // namespace nlohmann::detail +#elif JSON_HAS_FILESYSTEM +#include +namespace nlohmann::detail +{ +namespace std_fs = std::filesystem; +} // namespace nlohmann::detail #endif namespace nlohmann @@ -391,9 +401,9 @@ void to_json(BasicJsonType& j, const T& t) to_json_tuple_impl(j, t, make_index_sequence::value> {}); } -#ifdef JSON_HAS_CPP_17 +#if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM template -void to_json(BasicJsonType& j, const std::filesystem::path& p) +void to_json(BasicJsonType& j, const std_fs::path& p) { j = p.string(); } diff --git a/include/nlohmann/detail/input/binary_reader.hpp b/include/nlohmann/detail/input/binary_reader.hpp index 3add2c1150..65e0047ac7 100644 --- a/include/nlohmann/detail/input/binary_reader.hpp +++ b/include/nlohmann/detail/input/binary_reader.hpp @@ -161,7 +161,7 @@ class binary_reader std::int32_t document_size{}; get_number(input_format_t::bson, document_size); - if (JSON_HEDLEY_UNLIKELY(!sax->start_object(std::size_t(-1)))) + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast(-1)))) { return false; } @@ -318,7 +318,7 @@ class binary_reader default: // anything else not supported (yet) { std::array cr{{}}; - (std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast(element_type)); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) + static_cast((std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast(element_type))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) return sax->parse_error(element_type_parse_position, std::string(cr.data()), parse_error::create(114, element_type_parse_position, "Unsupported BSON record type 0x" + std::string(cr.data()), BasicJsonType())); } } @@ -379,7 +379,7 @@ class binary_reader std::int32_t document_size{}; get_number(input_format_t::bson, document_size); - if (JSON_HEDLEY_UNLIKELY(!sax->start_array(std::size_t(-1)))) + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast(-1)))) { return false; } @@ -638,7 +638,7 @@ class binary_reader } case 0x9F: // array (indefinite length) - return get_cbor_array(std::size_t(-1), tag_handler); + return get_cbor_array(static_cast(-1), tag_handler); // map (0x00..0x17 pairs of data items follow) case 0xA0: @@ -692,7 +692,7 @@ class binary_reader } case 0xBF: // map (indefinite length) - return get_cbor_object(std::size_t(-1), tag_handler); + return get_cbor_object(static_cast(-1), tag_handler); case 0xC6: // tagged item case 0xC7: @@ -1076,7 +1076,7 @@ class binary_reader } /*! - @param[in] len the length of the array or std::size_t(-1) for an + @param[in] len the length of the array or static_cast(-1) for an array of indefinite size @param[in] tag_handler how CBOR tags should be treated @return whether array creation completed @@ -1089,7 +1089,7 @@ class binary_reader return false; } - if (len != std::size_t(-1)) + if (len != static_cast(-1)) { for (std::size_t i = 0; i < len; ++i) { @@ -1114,7 +1114,7 @@ class binary_reader } /*! - @param[in] len the length of the object or std::size_t(-1) for an + @param[in] len the length of the object or static_cast(-1) for an object of indefinite size @param[in] tag_handler how CBOR tags should be treated @return whether object creation completed @@ -1130,7 +1130,7 @@ class binary_reader if (len != 0) { string_t key; - if (len != std::size_t(-1)) + if (len != static_cast(-1)) { for (std::size_t i = 0; i < len; ++i) { @@ -2140,7 +2140,7 @@ class binary_reader } else { - if (JSON_HEDLEY_UNLIKELY(!sax->start_array(std::size_t(-1)))) + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast(-1)))) { return false; } @@ -2210,7 +2210,7 @@ class binary_reader } else { - if (JSON_HEDLEY_UNLIKELY(!sax->start_object(std::size_t(-1)))) + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast(-1)))) { return false; } @@ -2462,7 +2462,7 @@ class binary_reader std::string get_token_string() const { std::array cr{{}}; - (std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast(current)); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) + static_cast((std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast(current))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) return std::string{cr.data()}; } diff --git a/include/nlohmann/detail/input/json_sax.hpp b/include/nlohmann/detail/input/json_sax.hpp index 67278f8566..250f113dda 100644 --- a/include/nlohmann/detail/input/json_sax.hpp +++ b/include/nlohmann/detail/input/json_sax.hpp @@ -222,7 +222,7 @@ class json_sax_dom_parser { ref_stack.push_back(handle_value(BasicJsonType::value_t::object)); - if (JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size())) + if (JSON_HEDLEY_UNLIKELY(len != static_cast(-1) && len > ref_stack.back()->max_size())) { JSON_THROW(out_of_range::create(408, "excessive object size: " + std::to_string(len), *ref_stack.back())); } @@ -248,7 +248,7 @@ class json_sax_dom_parser { ref_stack.push_back(handle_value(BasicJsonType::value_t::array)); - if (JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size())) + if (JSON_HEDLEY_UNLIKELY(len != static_cast(-1) && len > ref_stack.back()->max_size())) { JSON_THROW(out_of_range::create(408, "excessive array size: " + std::to_string(len), *ref_stack.back())); } @@ -403,7 +403,7 @@ class json_sax_dom_callback_parser ref_stack.push_back(val.second); // check object limit - if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size())) + if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != static_cast(-1) && len > ref_stack.back()->max_size())) { JSON_THROW(out_of_range::create(408, "excessive object size: " + std::to_string(len), *ref_stack.back())); } @@ -473,7 +473,7 @@ class json_sax_dom_callback_parser ref_stack.push_back(val.second); // check array limit - if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size())) + if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != static_cast(-1) && len > ref_stack.back()->max_size())) { JSON_THROW(out_of_range::create(408, "excessive array size: " + std::to_string(len), *ref_stack.back())); } @@ -676,7 +676,7 @@ class json_sax_acceptor return true; } - bool start_object(std::size_t /*unused*/ = std::size_t(-1)) + bool start_object(std::size_t /*unused*/ = static_cast(-1)) { return true; } @@ -691,7 +691,7 @@ class json_sax_acceptor return true; } - bool start_array(std::size_t /*unused*/ = std::size_t(-1)) + bool start_array(std::size_t /*unused*/ = static_cast(-1)) { return true; } diff --git a/include/nlohmann/detail/input/lexer.hpp b/include/nlohmann/detail/input/lexer.hpp index 3a47167e9c..adaf01e387 100644 --- a/include/nlohmann/detail/input/lexer.hpp +++ b/include/nlohmann/detail/input/lexer.hpp @@ -1447,7 +1447,7 @@ class lexer : public lexer_base { // escape control characters std::array cs{{}}; - (std::snprintf)(cs.data(), cs.size(), "", static_cast(c)); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) + static_cast((std::snprintf)(cs.data(), cs.size(), "", static_cast(c))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) result += cs.data(); } else @@ -1541,17 +1541,17 @@ class lexer : public lexer_base // literals case 't': { - std::array true_literal = {{char_type('t'), char_type('r'), char_type('u'), char_type('e')}}; + std::array true_literal = {{static_cast('t'), static_cast('r'), static_cast('u'), static_cast('e')}}; return scan_literal(true_literal.data(), true_literal.size(), token_type::literal_true); } case 'f': { - std::array false_literal = {{char_type('f'), char_type('a'), char_type('l'), char_type('s'), char_type('e')}}; + std::array false_literal = {{static_cast('f'), static_cast('a'), static_cast('l'), static_cast('s'), static_cast('e')}}; return scan_literal(false_literal.data(), false_literal.size(), token_type::literal_false); } case 'n': { - std::array null_literal = {{char_type('n'), char_type('u'), char_type('l'), char_type('l')}}; + std::array null_literal = {{static_cast('n'), static_cast('u'), static_cast('l'), static_cast('l')}}; return scan_literal(null_literal.data(), null_literal.size(), token_type::literal_null); } diff --git a/include/nlohmann/detail/input/parser.hpp b/include/nlohmann/detail/input/parser.hpp index 99cdd05ecb..024dd040f7 100644 --- a/include/nlohmann/detail/input/parser.hpp +++ b/include/nlohmann/detail/input/parser.hpp @@ -186,7 +186,7 @@ class parser { case token_type::begin_object: { - if (JSON_HEDLEY_UNLIKELY(!sax->start_object(std::size_t(-1)))) + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast(-1)))) { return false; } @@ -231,7 +231,7 @@ class parser case token_type::begin_array: { - if (JSON_HEDLEY_UNLIKELY(!sax->start_array(std::size_t(-1)))) + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast(-1)))) { return false; } diff --git a/include/nlohmann/detail/macro_scope.hpp b/include/nlohmann/detail/macro_scope.hpp index c2a65bdda6..8b4f7c0644 100644 --- a/include/nlohmann/detail/macro_scope.hpp +++ b/include/nlohmann/detail/macro_scope.hpp @@ -37,6 +37,66 @@ #define JSON_HAS_CPP_11 #endif +#if !defined(JSON_HAS_FILESYSTEM) && !defined(JSON_HAS_EXPERIMENTAL_FILESYSTEM) + #ifdef JSON_HAS_CPP_17 + #if defined(__cpp_lib_filesystem) + #define JSON_HAS_FILESYSTEM 1 + #elif defined(__cpp_lib_experimental_filesystem) + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 + #elif !defined(__has_include) + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 + #elif __has_include() + #define JSON_HAS_FILESYSTEM 1 + #elif __has_include() + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 + #endif + + // std::filesystem does not work on MinGW GCC 8: https://sourceforge.net/p/mingw-w64/bugs/737/ + #if defined(__MINGW32__) && defined(__GNUC__) && __GNUC__ == 8 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before GCC 8: https://en.cppreference.com/w/cpp/compiler_support + #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 8 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before Clang 7: https://en.cppreference.com/w/cpp/compiler_support + #if defined(__clang_major__) && __clang_major__ < 7 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before MSVC 19.14: https://en.cppreference.com/w/cpp/compiler_support + #if defined(_MSC_VER) && _MSC_VER < 1940 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before iOS 13 + #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before macOS Catalina + #if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + #endif +#endif + +#ifndef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 0 +#endif + +#ifndef JSON_HAS_FILESYSTEM + #define JSON_HAS_FILESYSTEM 0 +#endif + // disable documentation warnings on clang #if defined(__clang__) #pragma clang diagnostic push diff --git a/include/nlohmann/detail/macro_unscope.hpp b/include/nlohmann/detail/macro_unscope.hpp index 67bf1466bc..1a29fb5e00 100644 --- a/include/nlohmann/detail/macro_unscope.hpp +++ b/include/nlohmann/detail/macro_unscope.hpp @@ -16,6 +16,8 @@ #undef JSON_HAS_CPP_14 #undef JSON_HAS_CPP_17 #undef JSON_HAS_CPP_20 +#undef JSON_HAS_FILESYSTEM +#undef JSON_HAS_EXPERIMENTAL_FILESYSTEM #undef NLOHMANN_BASIC_JSON_TPL_DECLARATION #undef NLOHMANN_BASIC_JSON_TPL #undef JSON_EXPLICIT diff --git a/include/nlohmann/detail/meta/cpp_future.hpp b/include/nlohmann/detail/meta/cpp_future.hpp index e24518fafe..147f2fa357 100644 --- a/include/nlohmann/detail/meta/cpp_future.hpp +++ b/include/nlohmann/detail/meta/cpp_future.hpp @@ -148,7 +148,7 @@ struct static_const }; template -constexpr T static_const::value; +constexpr T static_const::value; // NOLINT(readability-redundant-declaration) } // namespace detail } // namespace nlohmann diff --git a/include/nlohmann/detail/output/binary_writer.hpp b/include/nlohmann/detail/output/binary_writer.hpp index 23b9ff16e0..598587141f 100644 --- a/include/nlohmann/detail/output/binary_writer.hpp +++ b/include/nlohmann/detail/output/binary_writer.hpp @@ -1083,7 +1083,7 @@ class binary_writer { std::size_t array_index = 0ul; - const std::size_t embedded_document_size = std::accumulate(std::begin(value), std::end(value), std::size_t(0), [&array_index](std::size_t result, const typename BasicJsonType::array_t::value_type & el) + const std::size_t embedded_document_size = std::accumulate(std::begin(value), std::end(value), static_cast(0), [&array_index](std::size_t result, const typename BasicJsonType::array_t::value_type & el) { return result + calc_bson_element_size(std::to_string(array_index++), el); }); @@ -1127,7 +1127,7 @@ class binary_writer write_bson_entry_header(name, 0x05); write_number(static_cast(value.size())); - write_number(value.has_subtype() ? static_cast(value.subtype()) : std::uint8_t(0x00)); + write_number(value.has_subtype() ? static_cast(value.subtype()) : static_cast(0x00)); oa->write_characters(reinterpret_cast(value.data()), value.size()); } @@ -1233,7 +1233,7 @@ class binary_writer */ static std::size_t calc_bson_object_size(const typename BasicJsonType::object_t& value) { - std::size_t document_size = std::accumulate(value.begin(), value.end(), std::size_t(0), + std::size_t document_size = std::accumulate(value.begin(), value.end(), static_cast(0), [](size_t result, const typename BasicJsonType::object_t::value_type & el) { return result += calc_bson_element_size(el.first, el.second); diff --git a/include/nlohmann/detail/output/serializer.hpp b/include/nlohmann/detail/output/serializer.hpp index 07fa3e9682..0b49c5bca4 100644 --- a/include/nlohmann/detail/output/serializer.hpp +++ b/include/nlohmann/detail/output/serializer.hpp @@ -457,16 +457,16 @@ class serializer if (codepoint <= 0xFFFF) { // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg) - (std::snprintf)(string_buffer.data() + bytes, 7, "\\u%04x", - static_cast(codepoint)); + static_cast((std::snprintf)(string_buffer.data() + bytes, 7, "\\u%04x", + static_cast(codepoint))); bytes += 6; } else { // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg) - (std::snprintf)(string_buffer.data() + bytes, 13, "\\u%04x\\u%04x", - static_cast(0xD7C0u + (codepoint >> 10u)), - static_cast(0xDC00u + (codepoint & 0x3FFu))); + static_cast((std::snprintf)(string_buffer.data() + bytes, 13, "\\u%04x\\u%04x", + static_cast(0xD7C0u + (codepoint >> 10u)), + static_cast(0xDC00u + (codepoint & 0x3FFu)))); bytes += 12; } } diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index 16c9353ca1..1af58d1d62 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -1031,25 +1031,25 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec case value_t::boolean: { - boolean = boolean_t(false); + boolean = static_cast(false); break; } case value_t::number_integer: { - number_integer = number_integer_t(0); + number_integer = static_cast(0); break; } case value_t::number_unsigned: { - number_unsigned = number_unsigned_t(0); + number_unsigned = static_cast(0); break; } case value_t::number_float: { - number_float = number_float_t(0.0); + number_float = static_cast(0.0); break; } @@ -1291,10 +1291,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec return it; } - reference set_parent(reference j, std::size_t old_capacity = std::size_t(-1)) + reference set_parent(reference j, std::size_t old_capacity = static_cast(-1)) { #if JSON_DIAGNOSTICS - if (old_capacity != std::size_t(-1)) + if (old_capacity != static_cast(-1)) { // see https://github.com/nlohmann/json/issues/2838 JSON_ASSERT(type() == value_t::array); diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 5dce1b1deb..e2239669fd 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -2325,6 +2325,66 @@ using is_detected_convertible = #define JSON_HAS_CPP_11 #endif +#if !defined(JSON_HAS_FILESYSTEM) && !defined(JSON_HAS_EXPERIMENTAL_FILESYSTEM) + #ifdef JSON_HAS_CPP_17 + #if defined(__cpp_lib_filesystem) + #define JSON_HAS_FILESYSTEM 1 + #elif defined(__cpp_lib_experimental_filesystem) + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 + #elif !defined(__has_include) + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 + #elif __has_include() + #define JSON_HAS_FILESYSTEM 1 + #elif __has_include() + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 + #endif + + // std::filesystem does not work on MinGW GCC 8: https://sourceforge.net/p/mingw-w64/bugs/737/ + #if defined(__MINGW32__) && defined(__GNUC__) && __GNUC__ == 8 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before GCC 8: https://en.cppreference.com/w/cpp/compiler_support + #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 8 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before Clang 7: https://en.cppreference.com/w/cpp/compiler_support + #if defined(__clang_major__) && __clang_major__ < 7 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before MSVC 19.14: https://en.cppreference.com/w/cpp/compiler_support + #if defined(_MSC_VER) && _MSC_VER < 1940 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before iOS 13 + #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before macOS Catalina + #if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + #endif +#endif + +#ifndef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 0 +#endif + +#ifndef JSON_HAS_FILESYSTEM + #define JSON_HAS_FILESYSTEM 0 +#endif + // disable documentation warnings on clang #if defined(__clang__) #pragma clang diagnostic push @@ -3298,7 +3358,7 @@ struct static_const }; template -constexpr T static_const::value; +constexpr T static_const::value; // NOLINT(readability-redundant-declaration) } // namespace detail } // namespace nlohmann @@ -3950,8 +4010,18 @@ T conditional_static_cast(U value) // #include -#ifdef JSON_HAS_CPP_17 - #include +#if JSON_HAS_EXPERIMENTAL_FILESYSTEM +#include +namespace nlohmann::detail +{ +namespace std_fs = std::experimental::filesystem; +} // namespace nlohmann::detail +#elif JSON_HAS_FILESYSTEM +#include +namespace nlohmann::detail +{ +namespace std_fs = std::filesystem; +} // namespace nlohmann::detail #endif namespace nlohmann @@ -4379,9 +4449,9 @@ void from_json(const BasicJsonType& j, std::unordered_map -void from_json(const BasicJsonType& j, std::filesystem::path& p) +void from_json(const BasicJsonType& j, std_fs::path& p) { if (JSON_HEDLEY_UNLIKELY(!j.is_string())) { @@ -4626,8 +4696,18 @@ class tuple_element> // #include -#ifdef JSON_HAS_CPP_17 - #include +#if JSON_HAS_EXPERIMENTAL_FILESYSTEM +#include +namespace nlohmann::detail +{ +namespace std_fs = std::experimental::filesystem; +} // namespace nlohmann::detail +#elif JSON_HAS_FILESYSTEM +#include +namespace nlohmann::detail +{ +namespace std_fs = std::filesystem; +} // namespace nlohmann::detail #endif namespace nlohmann @@ -5002,9 +5082,9 @@ void to_json(BasicJsonType& j, const T& t) to_json_tuple_impl(j, t, make_index_sequence::value> {}); } -#ifdef JSON_HAS_CPP_17 +#if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM template -void to_json(BasicJsonType& j, const std::filesystem::path& p) +void to_json(BasicJsonType& j, const std_fs::path& p) { j = p.string(); } @@ -5214,7 +5294,7 @@ class byte_container_with_subtype : public BinaryType */ constexpr subtype_type subtype() const noexcept { - return m_has_subtype ? m_subtype : subtype_type(-1); + return m_has_subtype ? m_subtype : static_cast(-1); } /*! @@ -6134,7 +6214,7 @@ class json_sax_dom_parser { ref_stack.push_back(handle_value(BasicJsonType::value_t::object)); - if (JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size())) + if (JSON_HEDLEY_UNLIKELY(len != static_cast(-1) && len > ref_stack.back()->max_size())) { JSON_THROW(out_of_range::create(408, "excessive object size: " + std::to_string(len), *ref_stack.back())); } @@ -6160,7 +6240,7 @@ class json_sax_dom_parser { ref_stack.push_back(handle_value(BasicJsonType::value_t::array)); - if (JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size())) + if (JSON_HEDLEY_UNLIKELY(len != static_cast(-1) && len > ref_stack.back()->max_size())) { JSON_THROW(out_of_range::create(408, "excessive array size: " + std::to_string(len), *ref_stack.back())); } @@ -6315,7 +6395,7 @@ class json_sax_dom_callback_parser ref_stack.push_back(val.second); // check object limit - if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size())) + if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != static_cast(-1) && len > ref_stack.back()->max_size())) { JSON_THROW(out_of_range::create(408, "excessive object size: " + std::to_string(len), *ref_stack.back())); } @@ -6385,7 +6465,7 @@ class json_sax_dom_callback_parser ref_stack.push_back(val.second); // check array limit - if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size())) + if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != static_cast(-1) && len > ref_stack.back()->max_size())) { JSON_THROW(out_of_range::create(408, "excessive array size: " + std::to_string(len), *ref_stack.back())); } @@ -6588,7 +6668,7 @@ class json_sax_acceptor return true; } - bool start_object(std::size_t /*unused*/ = std::size_t(-1)) + bool start_object(std::size_t /*unused*/ = static_cast(-1)) { return true; } @@ -6603,7 +6683,7 @@ class json_sax_acceptor return true; } - bool start_array(std::size_t /*unused*/ = std::size_t(-1)) + bool start_array(std::size_t /*unused*/ = static_cast(-1)) { return true; } @@ -8075,7 +8155,7 @@ class lexer : public lexer_base { // escape control characters std::array cs{{}}; - (std::snprintf)(cs.data(), cs.size(), "", static_cast(c)); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) + static_cast((std::snprintf)(cs.data(), cs.size(), "", static_cast(c))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) result += cs.data(); } else @@ -8169,17 +8249,17 @@ class lexer : public lexer_base // literals case 't': { - std::array true_literal = {{char_type('t'), char_type('r'), char_type('u'), char_type('e')}}; + std::array true_literal = {{static_cast('t'), static_cast('r'), static_cast('u'), static_cast('e')}}; return scan_literal(true_literal.data(), true_literal.size(), token_type::literal_true); } case 'f': { - std::array false_literal = {{char_type('f'), char_type('a'), char_type('l'), char_type('s'), char_type('e')}}; + std::array false_literal = {{static_cast('f'), static_cast('a'), static_cast('l'), static_cast('s'), static_cast('e')}}; return scan_literal(false_literal.data(), false_literal.size(), token_type::literal_false); } case 'n': { - std::array null_literal = {{char_type('n'), char_type('u'), char_type('l'), char_type('l')}}; + std::array null_literal = {{static_cast('n'), static_cast('u'), static_cast('l'), static_cast('l')}}; return scan_literal(null_literal.data(), null_literal.size(), token_type::literal_null); } @@ -8549,7 +8629,7 @@ class binary_reader std::int32_t document_size{}; get_number(input_format_t::bson, document_size); - if (JSON_HEDLEY_UNLIKELY(!sax->start_object(std::size_t(-1)))) + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast(-1)))) { return false; } @@ -8706,7 +8786,7 @@ class binary_reader default: // anything else not supported (yet) { std::array cr{{}}; - (std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast(element_type)); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) + static_cast((std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast(element_type))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) return sax->parse_error(element_type_parse_position, std::string(cr.data()), parse_error::create(114, element_type_parse_position, "Unsupported BSON record type 0x" + std::string(cr.data()), BasicJsonType())); } } @@ -8767,7 +8847,7 @@ class binary_reader std::int32_t document_size{}; get_number(input_format_t::bson, document_size); - if (JSON_HEDLEY_UNLIKELY(!sax->start_array(std::size_t(-1)))) + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast(-1)))) { return false; } @@ -9026,7 +9106,7 @@ class binary_reader } case 0x9F: // array (indefinite length) - return get_cbor_array(std::size_t(-1), tag_handler); + return get_cbor_array(static_cast(-1), tag_handler); // map (0x00..0x17 pairs of data items follow) case 0xA0: @@ -9080,7 +9160,7 @@ class binary_reader } case 0xBF: // map (indefinite length) - return get_cbor_object(std::size_t(-1), tag_handler); + return get_cbor_object(static_cast(-1), tag_handler); case 0xC6: // tagged item case 0xC7: @@ -9464,7 +9544,7 @@ class binary_reader } /*! - @param[in] len the length of the array or std::size_t(-1) for an + @param[in] len the length of the array or static_cast(-1) for an array of indefinite size @param[in] tag_handler how CBOR tags should be treated @return whether array creation completed @@ -9477,7 +9557,7 @@ class binary_reader return false; } - if (len != std::size_t(-1)) + if (len != static_cast(-1)) { for (std::size_t i = 0; i < len; ++i) { @@ -9502,7 +9582,7 @@ class binary_reader } /*! - @param[in] len the length of the object or std::size_t(-1) for an + @param[in] len the length of the object or static_cast(-1) for an object of indefinite size @param[in] tag_handler how CBOR tags should be treated @return whether object creation completed @@ -9518,7 +9598,7 @@ class binary_reader if (len != 0) { string_t key; - if (len != std::size_t(-1)) + if (len != static_cast(-1)) { for (std::size_t i = 0; i < len; ++i) { @@ -10528,7 +10608,7 @@ class binary_reader } else { - if (JSON_HEDLEY_UNLIKELY(!sax->start_array(std::size_t(-1)))) + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast(-1)))) { return false; } @@ -10598,7 +10678,7 @@ class binary_reader } else { - if (JSON_HEDLEY_UNLIKELY(!sax->start_object(std::size_t(-1)))) + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast(-1)))) { return false; } @@ -10850,7 +10930,7 @@ class binary_reader std::string get_token_string() const { std::array cr{{}}; - (std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast(current)); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) + static_cast((std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast(current))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) return std::string{cr.data()}; } @@ -11111,7 +11191,7 @@ class parser { case token_type::begin_object: { - if (JSON_HEDLEY_UNLIKELY(!sax->start_object(std::size_t(-1)))) + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast(-1)))) { return false; } @@ -11156,7 +11236,7 @@ class parser case token_type::begin_array: { - if (JSON_HEDLEY_UNLIKELY(!sax->start_array(std::size_t(-1)))) + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast(-1)))) { return false; } @@ -14750,7 +14830,7 @@ class binary_writer { std::size_t array_index = 0ul; - const std::size_t embedded_document_size = std::accumulate(std::begin(value), std::end(value), std::size_t(0), [&array_index](std::size_t result, const typename BasicJsonType::array_t::value_type & el) + const std::size_t embedded_document_size = std::accumulate(std::begin(value), std::end(value), static_cast(0), [&array_index](std::size_t result, const typename BasicJsonType::array_t::value_type & el) { return result + calc_bson_element_size(std::to_string(array_index++), el); }); @@ -14794,7 +14874,7 @@ class binary_writer write_bson_entry_header(name, 0x05); write_number(static_cast(value.size())); - write_number(value.has_subtype() ? static_cast(value.subtype()) : std::uint8_t(0x00)); + write_number(value.has_subtype() ? static_cast(value.subtype()) : static_cast(0x00)); oa->write_characters(reinterpret_cast(value.data()), value.size()); } @@ -14900,7 +14980,7 @@ class binary_writer */ static std::size_t calc_bson_object_size(const typename BasicJsonType::object_t& value) { - std::size_t document_size = std::accumulate(value.begin(), value.end(), std::size_t(0), + std::size_t document_size = std::accumulate(value.begin(), value.end(), static_cast(0), [](size_t result, const typename BasicJsonType::object_t::value_type & el) { return result += calc_bson_element_size(el.first, el.second); @@ -16881,16 +16961,16 @@ class serializer if (codepoint <= 0xFFFF) { // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg) - (std::snprintf)(string_buffer.data() + bytes, 7, "\\u%04x", - static_cast(codepoint)); + static_cast((std::snprintf)(string_buffer.data() + bytes, 7, "\\u%04x", + static_cast(codepoint))); bytes += 6; } else { // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg) - (std::snprintf)(string_buffer.data() + bytes, 13, "\\u%04x\\u%04x", - static_cast(0xD7C0u + (codepoint >> 10u)), - static_cast(0xDC00u + (codepoint & 0x3FFu))); + static_cast((std::snprintf)(string_buffer.data() + bytes, 13, "\\u%04x\\u%04x", + static_cast(0xD7C0u + (codepoint >> 10u)), + static_cast(0xDC00u + (codepoint & 0x3FFu)))); bytes += 12; } } @@ -18571,25 +18651,25 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec case value_t::boolean: { - boolean = boolean_t(false); + boolean = static_cast(false); break; } case value_t::number_integer: { - number_integer = number_integer_t(0); + number_integer = static_cast(0); break; } case value_t::number_unsigned: { - number_unsigned = number_unsigned_t(0); + number_unsigned = static_cast(0); break; } case value_t::number_float: { - number_float = number_float_t(0.0); + number_float = static_cast(0.0); break; } @@ -18831,10 +18911,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec return it; } - reference set_parent(reference j, std::size_t old_capacity = std::size_t(-1)) + reference set_parent(reference j, std::size_t old_capacity = static_cast(-1)) { #if JSON_DIAGNOSTICS - if (old_capacity != std::size_t(-1)) + if (old_capacity != static_cast(-1)) { // see https://github.com/nlohmann/json/issues/2838 JSON_ASSERT(type() == value_t::array); @@ -26588,6 +26668,8 @@ inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std #undef JSON_HAS_CPP_14 #undef JSON_HAS_CPP_17 #undef JSON_HAS_CPP_20 +#undef JSON_HAS_FILESYSTEM +#undef JSON_HAS_EXPERIMENTAL_FILESYSTEM #undef NLOHMANN_BASIC_JSON_TPL_DECLARATION #undef NLOHMANN_BASIC_JSON_TPL #undef JSON_EXPLICIT diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 447192cb0f..4c741f2743 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -52,6 +52,21 @@ endif() # one executable for each unit test file ############################################################################# +# check if compiler supports C++17 +foreach(feature ${CMAKE_CXX_COMPILE_FEATURES}) + if (${feature} STREQUAL cxx_std_17) + set(compiler_supports_cpp_17 TRUE) + endif() +endforeach() +# Clang only supports C++17 starting from Clang 5.0 +if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0) + unset(compiler_supports_cpp_17) +endif() +# MSVC 2015 (14.0) does not support C++17 +if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "MSVC" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19.1) + unset(compiler_supports_cpp_17) +endif() + file(GLOB files src/unit-*.cpp) foreach(file ${files}) @@ -68,6 +83,42 @@ foreach(file ${files}) target_include_directories(${testcase} PRIVATE ${CMAKE_BINARY_DIR}/include thirdparty/doctest thirdparty/fifo_map) target_link_libraries(${testcase} PRIVATE ${NLOHMANN_JSON_TARGET_NAME}) + # add a copy with C++17 compilation + if (compiler_supports_cpp_17) + file(READ ${file} FILE_CONTENT) + string(FIND "${FILE_CONTENT}" "JSON_HAS_CPP_17" CPP_17_FOUND) + if(NOT ${CPP_17_FOUND} EQUAL -1) + add_executable(${testcase}_cpp17 $ ${file}) + target_compile_definitions(${testcase}_cpp17 PRIVATE DOCTEST_CONFIG_SUPER_FAST_ASSERTS) + target_compile_options(${testcase}_cpp17 PRIVATE + $<$:/EHsc;$<$:/Od>> + $<$>:-Wno-deprecated;-Wno-float-equal> + $<$:-Wno-deprecated-declarations> + ) + target_include_directories(${testcase}_cpp17 PRIVATE ${CMAKE_BINARY_DIR}/include thirdparty/doctest thirdparty/fifo_map) + target_link_libraries(${testcase}_cpp17 PRIVATE ${NLOHMANN_JSON_TARGET_NAME}) + target_compile_features(${testcase}_cpp17 PRIVATE cxx_std_17) + + if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 8.0 AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.0 AND NOT MINGW) + # fix for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90050 + target_link_libraries(${testcase}_cpp17 PRIVATE stdc++fs) + endif() + + if (JSON_FastTests) + add_test(NAME "${testcase}_cpp17" + COMMAND ${testcase}_cpp17 ${DOCTEST_TEST_FILTER} + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + ) + else() + add_test(NAME "${testcase}_cpp17" + COMMAND ${testcase}_cpp17 ${DOCTEST_TEST_FILTER} --no-skip + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + ) + endif() + set_tests_properties("${testcase}_cpp17" PROPERTIES LABELS "all" FIXTURES_REQUIRED TEST_DATA) + endif() + endif() + if (JSON_FastTests) add_test(NAME "${testcase}" COMMAND ${testcase} ${DOCTEST_TEST_FILTER} diff --git a/test/src/unit-byte_container_with_subtype.cpp b/test/src/unit-byte_container_with_subtype.cpp index 51ce9c0f4f..9ff8ee9e95 100644 --- a/test/src/unit-byte_container_with_subtype.cpp +++ b/test/src/unit-byte_container_with_subtype.cpp @@ -41,11 +41,11 @@ TEST_CASE("byte_container_with_subtype") nlohmann::byte_container_with_subtype> container; CHECK(!container.has_subtype()); - CHECK(container.subtype() == subtype_type(-1)); + CHECK(container.subtype() == static_cast(-1)); container.clear_subtype(); CHECK(!container.has_subtype()); - CHECK(container.subtype() == subtype_type(-1)); + CHECK(container.subtype() == static_cast(-1)); container.set_subtype(42); CHECK(container.has_subtype()); @@ -60,7 +60,7 @@ TEST_CASE("byte_container_with_subtype") container.clear_subtype(); CHECK(!container.has_subtype()); - CHECK(container.subtype() == subtype_type(-1)); + CHECK(container.subtype() == static_cast(-1)); } SECTION("comparisons") diff --git a/test/src/unit-cbor.cpp b/test/src/unit-cbor.cpp index d67745e75a..95a2c8885d 100644 --- a/test/src/unit-cbor.cpp +++ b/test/src/unit-cbor.cpp @@ -610,7 +610,7 @@ TEST_CASE("CBOR") SECTION("-32768..-129 (int 16)") { - for (int16_t i = -32768; i <= int16_t(-129); ++i) + for (int16_t i = -32768; i <= static_cast(-129); ++i) { CAPTURE(i) diff --git a/test/src/unit-class_parser.cpp b/test/src/unit-class_parser.cpp index 22485048c1..9b3b4a1457 100644 --- a/test/src/unit-class_parser.cpp +++ b/test/src/unit-class_parser.cpp @@ -93,7 +93,7 @@ class SaxEventLogger bool start_object(std::size_t elements) { - if (elements == std::size_t(-1)) + if (elements == static_cast(-1)) { events.emplace_back("start_object()"); } @@ -118,7 +118,7 @@ class SaxEventLogger bool start_array(std::size_t elements) { - if (elements == std::size_t(-1)) + if (elements == static_cast(-1)) { events.emplace_back("start_array()"); } diff --git a/test/src/unit-deserialization.cpp b/test/src/unit-deserialization.cpp index 500966e9ee..25bd8699b9 100644 --- a/test/src/unit-deserialization.cpp +++ b/test/src/unit-deserialization.cpp @@ -93,7 +93,7 @@ struct SaxEventLogger : public nlohmann::json_sax bool start_object(std::size_t elements) override { - if (elements == std::size_t(-1)) + if (elements == static_cast(-1)) { events.emplace_back("start_object()"); } @@ -118,7 +118,7 @@ struct SaxEventLogger : public nlohmann::json_sax bool start_array(std::size_t elements) override { - if (elements == std::size_t(-1)) + if (elements == static_cast(-1)) { events.emplace_back("start_array()"); } @@ -148,7 +148,7 @@ struct SaxEventLoggerExitAfterStartObject : public SaxEventLogger { bool start_object(std::size_t elements) override { - if (elements == std::size_t(-1)) + if (elements == static_cast(-1)) { events.emplace_back("start_object()"); } @@ -173,7 +173,7 @@ struct SaxEventLoggerExitAfterStartArray : public SaxEventLogger { bool start_array(std::size_t elements) override { - if (elements == std::size_t(-1)) + if (elements == static_cast(-1)) { events.emplace_back("start_array()"); } diff --git a/test/src/unit-hash.cpp b/test/src/unit-hash.cpp index 7abec52d19..dc0614ae07 100644 --- a/test/src/unit-hash.cpp +++ b/test/src/unit-hash.cpp @@ -56,7 +56,7 @@ TEST_CASE("hash") // number hashes.insert(std::hash {}(json(0))); - hashes.insert(std::hash {}(json(unsigned(0)))); + hashes.insert(std::hash {}(json(static_cast(0)))); hashes.insert(std::hash {}(json(-1))); hashes.insert(std::hash {}(json(0.0))); @@ -105,7 +105,7 @@ TEST_CASE("hash") // number hashes.insert(std::hash {}(ordered_json(0))); - hashes.insert(std::hash {}(ordered_json(unsigned(0)))); + hashes.insert(std::hash {}(ordered_json(static_cast(0)))); hashes.insert(std::hash {}(ordered_json(-1))); hashes.insert(std::hash {}(ordered_json(0.0))); diff --git a/test/src/unit-msgpack.cpp b/test/src/unit-msgpack.cpp index 0ac9e30c1d..e593c364c0 100644 --- a/test/src/unit-msgpack.cpp +++ b/test/src/unit-msgpack.cpp @@ -446,7 +446,7 @@ TEST_CASE("MessagePack") SECTION("-32768..-129 (int 16)") { - for (int16_t i = -32768; i <= int16_t(-129); ++i) + for (int16_t i = -32768; i <= static_cast(-129); ++i) { CAPTURE(i) diff --git a/test/src/unit-regression1.cpp b/test/src/unit-regression1.cpp index 92c27ff4e2..e91bbda144 100644 --- a/test/src/unit-regression1.cpp +++ b/test/src/unit-regression1.cpp @@ -170,7 +170,7 @@ TEST_CASE("regression tests 1") json::number_float_t f1{j1}; CHECK(std::isnan(f1)); - json j2 = json::number_float_t(NAN); + json j2 = static_cast(NAN); CHECK(j2.is_number_float()); json::number_float_t f2{j2}; CHECK(std::isnan(f2)); @@ -183,7 +183,7 @@ TEST_CASE("regression tests 1") json::number_float_t f1{j1}; CHECK(!std::isfinite(f1)); - json j2 = json::number_float_t(INFINITY); + json j2 = static_cast(INFINITY); CHECK(j2.is_number_float()); json::number_float_t f2{j2}; CHECK(!std::isfinite(f2)); @@ -205,7 +205,7 @@ TEST_CASE("regression tests 1") // check if the actual value was stored CHECK(j2 == 102); - static_assert(std::is_same::value, ""); + static_assert(std::is_same::value, "types must be the same"); j.push_back(json::object( { @@ -567,17 +567,17 @@ TEST_CASE("regression tests 1") SECTION("issue #378 - locale-independent num-to-str") { - setlocale(LC_NUMERIC, "de_DE.UTF-8"); + static_cast(setlocale(LC_NUMERIC, "de_DE.UTF-8")); // verify that dumped correctly with '.' and no grouping const json j1 = 12345.67; CHECK(json(12345.67).dump() == "12345.67"); - setlocale(LC_NUMERIC, "C"); + static_cast(setlocale(LC_NUMERIC, "C")); } SECTION("issue #379 - locale-independent str-to-num") { - setlocale(LC_NUMERIC, "de_DE.UTF-8"); + static_cast(setlocale(LC_NUMERIC, "de_DE.UTF-8")); // verify that parsed correctly despite using strtod internally CHECK(json::parse("3.14").get() == 3.14); @@ -910,7 +910,7 @@ TEST_CASE("regression tests 1") ++i; } - std::remove("test.json"); + static_cast(std::remove("test.json")); } } diff --git a/test/src/unit-regression2.cpp b/test/src/unit-regression2.cpp index 3ae73ce182..afbdf3dbe0 100644 --- a/test/src/unit-regression2.cpp +++ b/test/src/unit-regression2.cpp @@ -47,10 +47,82 @@ using ordered_json = nlohmann::ordered_json; #endif #ifdef JSON_HAS_CPP_17 - #include #include + + #if !defined(JSON_HAS_FILESYSTEM) && !defined(JSON_HAS_EXPERIMENTAL_FILESYSTEM) + #if defined(__cpp_lib_filesystem) + #define JSON_HAS_FILESYSTEM 1 + #elif defined(__cpp_lib_experimental_filesystem) + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 + #elif !defined(__has_include) + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 + #elif __has_include() + #define JSON_HAS_FILESYSTEM 1 + #elif __has_include() + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 + #endif + + // std::filesystem does not work on MinGW GCC 8: https://sourceforge.net/p/mingw-w64/bugs/737/ + #if defined(__MINGW32__) && defined(__GNUC__) && __GNUC__ == 8 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before GCC 8: https://en.cppreference.com/w/cpp/compiler_support + #if defined(__GNUC__) && __GNUC__ < 8 && !defined(__clang__) + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before Clang 7: https://en.cppreference.com/w/cpp/compiler_support + #if defined(__clang_major__) && __clang_major__ < 7 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before MSVC 19.14: https://en.cppreference.com/w/cpp/compiler_support + #if defined(_MSC_VER) && _MSC_VER < 1940 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before iOS 13 + #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before macOS Catalina + #if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + #endif +#endif + +#ifndef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 0 +#endif + +#ifndef JSON_HAS_FILESYSTEM + #define JSON_HAS_FILESYSTEM 0 +#endif + +#if JSON_HAS_EXPERIMENTAL_FILESYSTEM +#include +namespace nlohmann::detail +{ +namespace std_fs = std::experimental::filesystem; +} // namespace nlohmann::detail +#elif JSON_HAS_FILESYSTEM +#include +namespace nlohmann::detail +{ +namespace std_fs = std::filesystem; +} // namespace nlohmann::detail #endif + #ifdef JSON_HAS_CPP_20 #include #endif @@ -351,9 +423,7 @@ TEST_CASE("regression tests 2") #ifdef JSON_HAS_CPP_17 SECTION("issue #1292 - Serializing std::variant causes stack overflow") { - static_assert( - !std::is_constructible>::value, - ""); + static_assert(!std::is_constructible>::value, "unexpected value"); } #endif @@ -492,15 +562,15 @@ TEST_CASE("regression tests 2") SECTION("issue #1805 - A pair is json constructible only if T1 and T2 are json constructible") { - static_assert(!std::is_constructible>::value, ""); - static_assert(!std::is_constructible>::value, ""); - static_assert(std::is_constructible>::value, ""); + static_assert(!std::is_constructible>::value, "unexpected result"); + static_assert(!std::is_constructible>::value, "unexpected result"); + static_assert(std::is_constructible>::value, "unexpected result"); } SECTION("issue #1825 - A tuple is json constructible only if all T in Args are json constructible") { - static_assert(!std::is_constructible>::value, ""); - static_assert(!std::is_constructible>::value, ""); - static_assert(std::is_constructible>::value, ""); + static_assert(!std::is_constructible>::value, "unexpected result"); + static_assert(!std::is_constructible>::value, "unexpected result"); + static_assert(std::is_constructible>::value, "unexpected result"); } SECTION("issue #1983 - JSON patch diff for op=add formation is not as per standard (RFC 6902)") @@ -697,7 +767,7 @@ TEST_CASE("regression tests 2") SECTION("issue #2825 - Properly constrain the basic_json conversion operator") { - static_assert(std::is_copy_assignable::value, ""); + static_assert(std::is_copy_assignable::value, "ordered_json must be copy assignable"); } SECTION("issue #2958 - Inserting in unordered json using a pointer retains the leading slash") @@ -728,14 +798,16 @@ TEST_CASE("regression tests 2") CHECK(j == k); } -#ifdef JSON_HAS_CPP_17 +#if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM SECTION("issue #3070 - Version 3.10.3 breaks backward-compatibility with 3.10.2 ") { - std::filesystem::path text_path("/tmp/text.txt"); + nlohmann::detail::std_fs::path text_path("/tmp/text.txt"); json j(text_path); - const auto j_path = j.get(); + const auto j_path = j.get(); CHECK(j_path == text_path); + + CHECK_THROWS_WITH_AS(nlohmann::detail::std_fs::path(json(1)), "[json.exception.type_error.302] type must be string, but is number", json::type_error); } #endif