From 39e27684ea5481d3599a87b1749cbf3db6c25d86 Mon Sep 17 00:00:00 2001 From: Florian Albrechtskirchinger Date: Tue, 21 Jun 2022 16:57:47 +0200 Subject: [PATCH 1/8] Use DOCTEST_* compiler macros and suppress pragmas warning (#3550) Use DOCTEST_* macros in place of predefined compiler macros for compiler detection and version checks. The suppression of warning -Wrange-loop-construct in unit-items.cpp causes GCC<11 to warn about pragmas. Suppressed by adding a version check. --- tests/src/unit-items.cpp | 4 +++- tests/src/unit-iterators2.cpp | 4 ++-- tests/src/unit-regression1.cpp | 2 +- tests/src/unit-regression2.cpp | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/tests/src/unit-items.cpp b/tests/src/unit-items.cpp index 64d92b59e..36c93e0d4 100644 --- a/tests/src/unit-items.cpp +++ b/tests/src/unit-items.cpp @@ -34,7 +34,9 @@ using nlohmann::json; // This test suite uses range for loops where values are copied. This is inefficient in usual code, but required to achieve 100% coverage. DOCTEST_GCC_SUPPRESS_WARNING_PUSH -DOCTEST_GCC_SUPPRESS_WARNING("-Wrange-loop-construct") +#if DOCTEST_GCC >= DOCTEST_COMPILER(11, 0, 0) + DOCTEST_GCC_SUPPRESS_WARNING("-Wrange-loop-construct") +#endif DOCTEST_CLANG_SUPPRESS_WARNING_PUSH DOCTEST_CLANG_SUPPRESS_WARNING("-Wrange-loop-construct") diff --git a/tests/src/unit-iterators2.cpp b/tests/src/unit-iterators2.cpp index b9c418c16..6b1d17ea8 100644 --- a/tests/src/unit-iterators2.cpp +++ b/tests/src/unit-iterators2.cpp @@ -916,7 +916,7 @@ TEST_CASE("iterators 2") } // libstdc++ algorithms don't work with Clang 15 (04/2022) -#if !defined(__clang__) || (defined(__clang__) && defined(__GLIBCXX__)) +#if !DOCTEST_CLANG || (DOCTEST_CLANG && defined(__GLIBCXX__)) SECTION("algorithms") { SECTION("copy") @@ -955,7 +955,7 @@ TEST_CASE("iterators 2") // libstdc++ views don't work with Clang 15 (04/2022) // libc++ hides limited ranges implementation behind guard macro -#if !(defined(__clang__) && (defined(__GLIBCXX__) || defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES))) +#if !(DOCTEST_CLANG && (defined(__GLIBCXX__) || defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES))) SECTION("views") { SECTION("reverse") diff --git a/tests/src/unit-regression1.cpp b/tests/src/unit-regression1.cpp index e6dfaa1c5..5a6e31e73 100644 --- a/tests/src/unit-regression1.cpp +++ b/tests/src/unit-regression1.cpp @@ -1520,7 +1520,7 @@ TEST_CASE("regression tests, exceptions dependent") ///////////////////////////////////////////////////////////////////// // the code below fails with Clang on Windows, so we need to exclude it there -#if defined(__clang__) && (defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__)) +#if DOCTEST_CLANG && (defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__)) #else template class array {}; template class object {}; diff --git a/tests/src/unit-regression2.cpp b/tests/src/unit-regression2.cpp index 3ee234eee..a41177174 100644 --- a/tests/src/unit-regression2.cpp +++ b/tests/src/unit-regression2.cpp @@ -803,7 +803,7 @@ TEST_CASE("regression tests 2") const auto j_path = j.get(); CHECK(j_path == text_path); -#if defined(__clang__) || ((defined(__GNUC__) && !defined(__INTEL_COMPILER)) && (__GNUC__ > 8 || (__GNUC__ == 8 && __GNUC_MINOR__ >= 4))) +#if DOCTEST_CLANG || DOCTEST_GCC >= DOCTEST_COMPILER(8, 4, 0) // only known to work on Clang and GCC >=8.4 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 From 954b10ad3baa5d92bb9cd5bb93c7258433cd2bb2 Mon Sep 17 00:00:00 2001 From: Alexander Karzhenkov Date: Sat, 25 Jun 2022 16:38:39 +0500 Subject: [PATCH 2/8] CI: fix "JSON_MultipleHeaders" option spelling (#3555) --- cmake/ci.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/ci.cmake b/cmake/ci.cmake index 4fcff86aa..e959edb56 100644 --- a/cmake/ci.cmake +++ b/cmake/ci.cmake @@ -595,7 +595,7 @@ add_custom_target(ci_test_amalgamation add_custom_target(ci_test_single_header COMMAND CXX=${GCC_TOOL} CXXFLAGS="${GCC_CXXFLAGS}" ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Debug -GNinja - -DJSON_BuildTests=ON -DJSON_MultipleHeader=OFF -DJSON_FastTests=ON + -DJSON_BuildTests=ON -DJSON_MultipleHeaders=OFF -DJSON_FastTests=ON -S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_single_header COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_single_header COMMAND cd ${PROJECT_BINARY_DIR}/build_single_header && ${CMAKE_CTEST_COMMAND} --parallel ${N} --output-on-failure From 7d361ec8efa8abf7bc126c2487389cfcc3469551 Mon Sep 17 00:00:00 2001 From: Florian Albrechtskirchinger Date: Mon, 4 Jul 2022 19:58:19 +0200 Subject: [PATCH 3/8] Add overloads for more key types to ordered_map and fix ordered_map::erase(first, last) with first == last (#3564) * Add overloads for more key types to ordered_map Add overloads to accept additional key types defined by type trait detail::is_usable_as_key_type to ordered_map. The same key types that can be used with json can now also be used with ordered_json. * Fix ordered_map::erase(first, last) with first == last * Modify element access unit test to also test ordered_json --- include/nlohmann/detail/meta/type_traits.hpp | 39 +- include/nlohmann/json.hpp | 20 +- include/nlohmann/ordered_map.hpp | 134 ++- single_include/nlohmann/json.hpp | 194 ++++- tests/src/unit-element_access2.cpp | 849 ++++++++++--------- 5 files changed, 741 insertions(+), 495 deletions(-) diff --git a/include/nlohmann/detail/meta/type_traits.hpp b/include/nlohmann/detail/meta/type_traits.hpp index cc3483122..f87d11d90 100644 --- a/include/nlohmann/detail/meta/type_traits.hpp +++ b/include/nlohmann/detail/meta/type_traits.hpp @@ -504,16 +504,23 @@ decltype(std::declval()(std::declval(), std::declval())), decltype(std::declval()(std::declval(), std::declval())) >> : std::true_type {}; -// checks if BasicJsonType::object_t::key_type and KeyType are comparable using Compare functor -template -using is_key_type_comparable = typename is_comparable < - typename BasicJsonType::object_comparator_t, - const key_type_t&, - KeyType >::type; - template using detect_is_transparent = typename T::is_transparent; +// type trait to check if KeyType can be used as object key (without a BasicJsonType) +// see is_usable_as_basic_json_key_type below +template> +using is_usable_as_key_type = typename std::conditional < + is_comparable::value + && !(ExcludeObjectKeyType && std::is_same::value) + && (!RequireTransparentComparator + || is_detected ::value) + && !is_json_pointer::value, + std::true_type, + std::false_type >::type; + // type trait to check if KeyType can be used as object key // true if: // - KeyType is comparable with BasicJsonType::object_t::key_type @@ -522,17 +529,13 @@ using detect_is_transparent = typename T::is_transparent; // - KeyType is not a JSON iterator or json_pointer template> -using is_usable_as_key_type = typename std::conditional < - is_key_type_comparable::value - && !(ExcludeObjectKeyType && std::is_same::value) - && (!RequireTransparentComparator || is_detected < - detect_is_transparent, - typename BasicJsonType::object_comparator_t >::value) - && !is_json_iterator_of::value - && !is_json_pointer::value, - std::true_type, - std::false_type >::type; +using is_usable_as_basic_json_key_type = typename std::conditional < + is_usable_as_key_type::value + && !is_json_iterator_of::value, + std::true_type, + std::false_type >::type; template using detect_erase_with_key_type = decltype(std::declval().erase(std::declval())); diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index 8fb894ce7..c8a71e259 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -2022,7 +2022,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief access specified object element with bounds checking /// @sa https://json.nlohmann.me/api/basic_json/at/ template::value, int> = 0> + detail::is_usable_as_basic_json_key_type::value, int> = 0> reference at(KeyType && key) { // at only works for objects @@ -2060,7 +2060,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief access specified object element with bounds checking /// @sa https://json.nlohmann.me/api/basic_json/at/ template::value, int> = 0> + detail::is_usable_as_basic_json_key_type::value, int> = 0> const_reference at(KeyType && key) const { // at only works for objects @@ -2190,7 +2190,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief access specified object element /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ template::value, int > = 0 > + detail::is_usable_as_basic_json_key_type::value, int > = 0 > reference operator[](KeyType && key) { // implicitly convert null value to an empty object @@ -2214,7 +2214,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief access specified object element /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ template::value, int > = 0 > + detail::is_usable_as_basic_json_key_type::value, int > = 0 > const_reference operator[](KeyType && key) const { // const operator[] only works for objects @@ -2283,7 +2283,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec template < class KeyType, class ValueType, detail::enable_if_t < detail::is_getable::value && !std::is_same::value - && detail::is_usable_as_key_type::value, int > = 0 > + && detail::is_usable_as_basic_json_key_type::value, int > = 0 > typename std::decay::type value(KeyType && key, ValueType && default_value) const { // value only works for objects @@ -2582,7 +2582,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief remove element from a JSON object given a key /// @sa https://json.nlohmann.me/api/basic_json/erase/ template::value, int> = 0> + detail::is_usable_as_basic_json_key_type::value, int> = 0> size_type erase(KeyType && key) { return erase_internal(std::forward(key)); @@ -2649,7 +2649,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief find an element in a JSON object /// @sa https://json.nlohmann.me/api/basic_json/find/ template::value, int> = 0> + detail::is_usable_as_basic_json_key_type::value, int> = 0> iterator find(KeyType && key) { auto result = end(); @@ -2665,7 +2665,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief find an element in a JSON object /// @sa https://json.nlohmann.me/api/basic_json/find/ template::value, int> = 0> + detail::is_usable_as_basic_json_key_type::value, int> = 0> const_iterator find(KeyType && key) const { auto result = cend(); @@ -2689,7 +2689,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief returns the number of occurrences of a key in a JSON object /// @sa https://json.nlohmann.me/api/basic_json/count/ template::value, int> = 0> + detail::is_usable_as_basic_json_key_type::value, int> = 0> size_type count(KeyType && key) const { // return 0 for all nonobject types @@ -2706,7 +2706,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief check the existence of an element in a JSON object /// @sa https://json.nlohmann.me/api/basic_json/contains/ template::value, int> = 0> + detail::is_usable_as_basic_json_key_type::value, int> = 0> bool contains(KeyType && key) const { return is_object() && m_value.object->find(std::forward(key)) != m_value.object->end(); diff --git a/include/nlohmann/ordered_map.hpp b/include/nlohmann/ordered_map.hpp index 6779fdf9a..d9000791b 100644 --- a/include/nlohmann/ordered_map.hpp +++ b/include/nlohmann/ordered_map.hpp @@ -10,6 +10,7 @@ #include // vector #include +#include namespace nlohmann { @@ -52,21 +53,50 @@ template , return {it, false}; } } - Container::emplace_back(key, t); - return {--this->end(), true}; + Container::emplace_back(key, std::forward(t)); + return {std::prev(this->end()), true}; } - T& operator[](const Key& key) + template::value, int> = 0> + std::pair emplace(KeyType && key, T && t) + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (m_compare(it->first, key)) + { + return {it, false}; + } + } + Container::emplace_back(std::forward(key), std::forward(t)); + return {std::prev(this->end()), true}; + } + + T& operator[](const key_type& key) { return emplace(key, T{}).first->second; } - const T& operator[](const Key& key) const + template::value, int> = 0> + T & operator[](KeyType && key) + { + return emplace(std::forward(key), T{}).first->second; + } + + const T& operator[](const key_type& key) const { return at(key); } - T& at(const Key& key) + template::value, int> = 0> + const T & operator[](KeyType && key) const + { + return at(std::forward(key)); + } + + T& at(const key_type& key) { for (auto it = this->begin(); it != this->end(); ++it) { @@ -79,7 +109,9 @@ template , JSON_THROW(std::out_of_range("key not found")); } - const T& at(const Key& key) const + template::value, int> = 0> + T & at(KeyType && key) { for (auto it = this->begin(); it != this->end(); ++it) { @@ -92,7 +124,56 @@ template , JSON_THROW(std::out_of_range("key not found")); } - size_type erase(const Key& key) + const T& at(const key_type& key) const + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (m_compare(it->first, key)) + { + return it->second; + } + } + + JSON_THROW(std::out_of_range("key not found")); + } + + template::value, int> = 0> + const T & at(KeyType && key) const + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (m_compare(it->first, key)) + { + return it->second; + } + } + + JSON_THROW(std::out_of_range("key not found")); + } + + size_type erase(const key_type& key) + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (m_compare(it->first, key)) + { + // Since we cannot move const Keys, re-construct them in place + for (auto next = it; ++next != this->end(); ++it) + { + it->~value_type(); // Destroy but keep allocation + new (&*it) value_type{std::move(*next)}; + } + Container::pop_back(); + return 1; + } + } + return 0; + } + + template::value, int> = 0> + size_type erase(KeyType && key) { for (auto it = this->begin(); it != this->end(); ++it) { @@ -118,6 +199,11 @@ template , iterator erase(iterator first, iterator last) { + if (first == last) + { + return first; + } + const auto elements_affected = std::distance(first, last); const auto offset = std::distance(Container::begin(), first); @@ -164,7 +250,7 @@ template , return Container::begin() + offset; } - size_type count(const Key& key) const + size_type count(const key_type& key) const { for (auto it = this->begin(); it != this->end(); ++it) { @@ -176,7 +262,21 @@ template , return 0; } - iterator find(const Key& key) + template::value, int> = 0> + size_type count(KeyType && key) const + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (m_compare(it->first, key)) + { + return 1; + } + } + return 0; + } + + iterator find(const key_type& key) { for (auto it = this->begin(); it != this->end(); ++it) { @@ -188,7 +288,21 @@ template , return Container::end(); } - const_iterator find(const Key& key) const + template::value, int> = 0> + iterator find(KeyType && key) + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (m_compare(it->first, key)) + { + return it; + } + } + return Container::end(); + } + + const_iterator find(const key_type& key) const { for (auto it = this->begin(); it != this->end(); ++it) { diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 50e5c805c..65670d92c 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -3699,16 +3699,23 @@ decltype(std::declval()(std::declval(), std::declval())), decltype(std::declval()(std::declval(), std::declval())) >> : std::true_type {}; -// checks if BasicJsonType::object_t::key_type and KeyType are comparable using Compare functor -template -using is_key_type_comparable = typename is_comparable < - typename BasicJsonType::object_comparator_t, - const key_type_t&, - KeyType >::type; - template using detect_is_transparent = typename T::is_transparent; +// type trait to check if KeyType can be used as object key (without a BasicJsonType) +// see is_usable_as_basic_json_key_type below +template> +using is_usable_as_key_type = typename std::conditional < + is_comparable::value + && !(ExcludeObjectKeyType && std::is_same::value) + && (!RequireTransparentComparator + || is_detected ::value) + && !is_json_pointer::value, + std::true_type, + std::false_type >::type; + // type trait to check if KeyType can be used as object key // true if: // - KeyType is comparable with BasicJsonType::object_t::key_type @@ -3717,17 +3724,13 @@ using detect_is_transparent = typename T::is_transparent; // - KeyType is not a JSON iterator or json_pointer template> -using is_usable_as_key_type = typename std::conditional < - is_key_type_comparable::value - && !(ExcludeObjectKeyType && std::is_same::value) - && (!RequireTransparentComparator || is_detected < - detect_is_transparent, - typename BasicJsonType::object_comparator_t >::value) - && !is_json_iterator_of::value - && !is_json_pointer::value, - std::true_type, - std::false_type >::type; +using is_usable_as_basic_json_key_type = typename std::conditional < + is_usable_as_key_type::value + && !is_json_iterator_of::value, + std::true_type, + std::false_type >::type; template using detect_erase_with_key_type = decltype(std::declval().erase(std::declval())); @@ -18265,6 +18268,8 @@ class serializer // #include +// #include + namespace nlohmann { @@ -18307,21 +18312,50 @@ template , return {it, false}; } } - Container::emplace_back(key, t); - return {--this->end(), true}; + Container::emplace_back(key, std::forward(t)); + return {std::prev(this->end()), true}; } - T& operator[](const Key& key) + template::value, int> = 0> + std::pair emplace(KeyType && key, T && t) + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (m_compare(it->first, key)) + { + return {it, false}; + } + } + Container::emplace_back(std::forward(key), std::forward(t)); + return {std::prev(this->end()), true}; + } + + T& operator[](const key_type& key) { return emplace(key, T{}).first->second; } - const T& operator[](const Key& key) const + template::value, int> = 0> + T & operator[](KeyType && key) + { + return emplace(std::forward(key), T{}).first->second; + } + + const T& operator[](const key_type& key) const { return at(key); } - T& at(const Key& key) + template::value, int> = 0> + const T & operator[](KeyType && key) const + { + return at(std::forward(key)); + } + + T& at(const key_type& key) { for (auto it = this->begin(); it != this->end(); ++it) { @@ -18334,7 +18368,9 @@ template , JSON_THROW(std::out_of_range("key not found")); } - const T& at(const Key& key) const + template::value, int> = 0> + T & at(KeyType && key) { for (auto it = this->begin(); it != this->end(); ++it) { @@ -18347,7 +18383,56 @@ template , JSON_THROW(std::out_of_range("key not found")); } - size_type erase(const Key& key) + const T& at(const key_type& key) const + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (m_compare(it->first, key)) + { + return it->second; + } + } + + JSON_THROW(std::out_of_range("key not found")); + } + + template::value, int> = 0> + const T & at(KeyType && key) const + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (m_compare(it->first, key)) + { + return it->second; + } + } + + JSON_THROW(std::out_of_range("key not found")); + } + + size_type erase(const key_type& key) + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (m_compare(it->first, key)) + { + // Since we cannot move const Keys, re-construct them in place + for (auto next = it; ++next != this->end(); ++it) + { + it->~value_type(); // Destroy but keep allocation + new (&*it) value_type{std::move(*next)}; + } + Container::pop_back(); + return 1; + } + } + return 0; + } + + template::value, int> = 0> + size_type erase(KeyType && key) { for (auto it = this->begin(); it != this->end(); ++it) { @@ -18373,6 +18458,11 @@ template , iterator erase(iterator first, iterator last) { + if (first == last) + { + return first; + } + const auto elements_affected = std::distance(first, last); const auto offset = std::distance(Container::begin(), first); @@ -18419,7 +18509,7 @@ template , return Container::begin() + offset; } - size_type count(const Key& key) const + size_type count(const key_type& key) const { for (auto it = this->begin(); it != this->end(); ++it) { @@ -18431,7 +18521,21 @@ template , return 0; } - iterator find(const Key& key) + template::value, int> = 0> + size_type count(KeyType && key) const + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (m_compare(it->first, key)) + { + return 1; + } + } + return 0; + } + + iterator find(const key_type& key) { for (auto it = this->begin(); it != this->end(); ++it) { @@ -18443,7 +18547,21 @@ template , return Container::end(); } - const_iterator find(const Key& key) const + template::value, int> = 0> + iterator find(KeyType && key) + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (m_compare(it->first, key)) + { + return it; + } + } + return Container::end(); + } + + const_iterator find(const key_type& key) const { for (auto it = this->begin(); it != this->end(); ++it) { @@ -20421,7 +20539,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief access specified object element with bounds checking /// @sa https://json.nlohmann.me/api/basic_json/at/ template::value, int> = 0> + detail::is_usable_as_basic_json_key_type::value, int> = 0> reference at(KeyType && key) { // at only works for objects @@ -20459,7 +20577,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief access specified object element with bounds checking /// @sa https://json.nlohmann.me/api/basic_json/at/ template::value, int> = 0> + detail::is_usable_as_basic_json_key_type::value, int> = 0> const_reference at(KeyType && key) const { // at only works for objects @@ -20589,7 +20707,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief access specified object element /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ template::value, int > = 0 > + detail::is_usable_as_basic_json_key_type::value, int > = 0 > reference operator[](KeyType && key) { // implicitly convert null value to an empty object @@ -20613,7 +20731,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief access specified object element /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/ template::value, int > = 0 > + detail::is_usable_as_basic_json_key_type::value, int > = 0 > const_reference operator[](KeyType && key) const { // const operator[] only works for objects @@ -20682,7 +20800,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec template < class KeyType, class ValueType, detail::enable_if_t < detail::is_getable::value && !std::is_same::value - && detail::is_usable_as_key_type::value, int > = 0 > + && detail::is_usable_as_basic_json_key_type::value, int > = 0 > typename std::decay::type value(KeyType && key, ValueType && default_value) const { // value only works for objects @@ -20981,7 +21099,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief remove element from a JSON object given a key /// @sa https://json.nlohmann.me/api/basic_json/erase/ template::value, int> = 0> + detail::is_usable_as_basic_json_key_type::value, int> = 0> size_type erase(KeyType && key) { return erase_internal(std::forward(key)); @@ -21048,7 +21166,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief find an element in a JSON object /// @sa https://json.nlohmann.me/api/basic_json/find/ template::value, int> = 0> + detail::is_usable_as_basic_json_key_type::value, int> = 0> iterator find(KeyType && key) { auto result = end(); @@ -21064,7 +21182,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief find an element in a JSON object /// @sa https://json.nlohmann.me/api/basic_json/find/ template::value, int> = 0> + detail::is_usable_as_basic_json_key_type::value, int> = 0> const_iterator find(KeyType && key) const { auto result = cend(); @@ -21088,7 +21206,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief returns the number of occurrences of a key in a JSON object /// @sa https://json.nlohmann.me/api/basic_json/count/ template::value, int> = 0> + detail::is_usable_as_basic_json_key_type::value, int> = 0> size_type count(KeyType && key) const { // return 0 for all nonobject types @@ -21105,7 +21223,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec /// @brief check the existence of an element in a JSON object /// @sa https://json.nlohmann.me/api/basic_json/contains/ template::value, int> = 0> + detail::is_usable_as_basic_json_key_type::value, int> = 0> bool contains(KeyType && key) const { return is_object() && m_value.object->find(std::forward(key)) != m_value.object->end(); diff --git a/tests/src/unit-element_access2.cpp b/tests/src/unit-element_access2.cpp index 11daba145..79307c362 100644 --- a/tests/src/unit-element_access2.cpp +++ b/tests/src/unit-element_access2.cpp @@ -30,67 +30,66 @@ SOFTWARE. #include "doctest_compatibility.h" #include -using nlohmann::json; -TEST_CASE("element access 2") +TEST_CASE_TEMPLATE("element access 2", Json, nlohmann::json, nlohmann::ordered_json) { SECTION("object") { - json j = {{"integer", 1}, {"unsigned", 1u}, {"floating", 42.23}, {"null", nullptr}, {"string", "hello world"}, {"boolean", true}, {"object", json::object()}, {"array", {1, 2, 3}}}; - const json j_const = j; + Json j = {{"integer", 1}, {"unsigned", 1u}, {"floating", 42.23}, {"null", nullptr}, {"string", "hello world"}, {"boolean", true}, {"object", Json::object()}, {"array", {1, 2, 3}}}; + const Json j_const = j; SECTION("access specified element with bounds checking") { SECTION("access within bounds") { - CHECK(j.at("integer") == json(1)); - CHECK(j.at("unsigned") == json(1u)); - CHECK(j.at("boolean") == json(true)); - CHECK(j.at("null") == json(nullptr)); - CHECK(j.at("string") == json("hello world")); - CHECK(j.at("floating") == json(42.23)); - CHECK(j.at("object") == json::object()); - CHECK(j.at("array") == json({1, 2, 3})); + CHECK(j.at("integer") == Json(1)); + CHECK(j.at("unsigned") == Json(1u)); + CHECK(j.at("boolean") == Json(true)); + CHECK(j.at("null") == Json(nullptr)); + CHECK(j.at("string") == Json("hello world")); + CHECK(j.at("floating") == Json(42.23)); + CHECK(j.at("object") == Json::object()); + CHECK(j.at("array") == Json({1, 2, 3})); - CHECK(j_const.at("integer") == json(1)); - CHECK(j_const.at("unsigned") == json(1u)); - CHECK(j_const.at("boolean") == json(true)); - CHECK(j_const.at("null") == json(nullptr)); - CHECK(j_const.at("string") == json("hello world")); - CHECK(j_const.at("floating") == json(42.23)); - CHECK(j_const.at("object") == json::object()); - CHECK(j_const.at("array") == json({1, 2, 3})); + CHECK(j_const.at("integer") == Json(1)); + CHECK(j_const.at("unsigned") == Json(1u)); + CHECK(j_const.at("boolean") == Json(true)); + CHECK(j_const.at("null") == Json(nullptr)); + CHECK(j_const.at("string") == Json("hello world")); + CHECK(j_const.at("floating") == Json(42.23)); + CHECK(j_const.at("object") == Json::object()); + CHECK(j_const.at("array") == Json({1, 2, 3})); #ifdef JSON_HAS_CPP_17 - CHECK(j.at(std::string_view("integer")) == json(1)); - CHECK(j.at(std::string_view("unsigned")) == json(1u)); - CHECK(j.at(std::string_view("boolean")) == json(true)); - CHECK(j.at(std::string_view("null")) == json(nullptr)); - CHECK(j.at(std::string_view("string")) == json("hello world")); - CHECK(j.at(std::string_view("floating")) == json(42.23)); - CHECK(j.at(std::string_view("object")) == json::object()); - CHECK(j.at(std::string_view("array")) == json({1, 2, 3})); + CHECK(j.at(std::string_view("integer")) == Json(1)); + CHECK(j.at(std::string_view("unsigned")) == Json(1u)); + CHECK(j.at(std::string_view("boolean")) == Json(true)); + CHECK(j.at(std::string_view("null")) == Json(nullptr)); + CHECK(j.at(std::string_view("string")) == Json("hello world")); + CHECK(j.at(std::string_view("floating")) == Json(42.23)); + CHECK(j.at(std::string_view("object")) == Json::object()); + CHECK(j.at(std::string_view("array")) == Json({1, 2, 3})); - CHECK(j_const.at(std::string_view("integer")) == json(1)); - CHECK(j_const.at(std::string_view("unsigned")) == json(1u)); - CHECK(j_const.at(std::string_view("boolean")) == json(true)); - CHECK(j_const.at(std::string_view("null")) == json(nullptr)); - CHECK(j_const.at(std::string_view("string")) == json("hello world")); - CHECK(j_const.at(std::string_view("floating")) == json(42.23)); - CHECK(j_const.at(std::string_view("object")) == json::object()); - CHECK(j_const.at(std::string_view("array")) == json({1, 2, 3})); + CHECK(j_const.at(std::string_view("integer")) == Json(1)); + CHECK(j_const.at(std::string_view("unsigned")) == Json(1u)); + CHECK(j_const.at(std::string_view("boolean")) == Json(true)); + CHECK(j_const.at(std::string_view("null")) == Json(nullptr)); + CHECK(j_const.at(std::string_view("string")) == Json("hello world")); + CHECK(j_const.at(std::string_view("floating")) == Json(42.23)); + CHECK(j_const.at(std::string_view("object")) == Json::object()); + CHECK(j_const.at(std::string_view("array")) == Json({1, 2, 3})); #endif } SECTION("access outside bounds") { - CHECK_THROWS_WITH_AS(j.at("foo"), "[json.exception.out_of_range.403] key 'foo' not found", json::out_of_range&); - CHECK_THROWS_WITH_AS(j_const.at("foo"), "[json.exception.out_of_range.403] key 'foo' not found", json::out_of_range&); + CHECK_THROWS_WITH_AS(j.at("foo"), "[json.exception.out_of_range.403] key 'foo' not found", typename Json::out_of_range&); + CHECK_THROWS_WITH_AS(j_const.at("foo"), "[json.exception.out_of_range.403] key 'foo' not found", typename Json::out_of_range&); #ifdef JSON_HAS_CPP_17 - CHECK_THROWS_WITH_AS(j.at(std::string_view("foo")), "[json.exception.out_of_range.403] key 'foo' not found", json::out_of_range&); - CHECK_THROWS_WITH_AS(j_const.at(std::string_view("foo")), "[json.exception.out_of_range.403] key 'foo' not found", json::out_of_range&); + CHECK_THROWS_WITH_AS(j.at(std::string_view("foo")), "[json.exception.out_of_range.403] key 'foo' not found", typename Json::out_of_range&); + CHECK_THROWS_WITH_AS(j_const.at(std::string_view("foo")), "[json.exception.out_of_range.403] key 'foo' not found", typename Json::out_of_range&); #endif } @@ -98,92 +97,92 @@ TEST_CASE("element access 2") { SECTION("null") { - json j_nonobject(json::value_t::null); - const json j_nonobject_const(j_nonobject); - CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with null", json::type_error&); - CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with null", json::type_error&); + Json j_nonobject(Json::value_t::null); + const Json j_nonobject_const(j_nonobject); + CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with null", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with null", typename Json::type_error&); #ifdef JSON_HAS_CPP_17 - CHECK_THROWS_WITH_AS(j_nonobject.at(std::string_view(std::string_view("foo"))), "[json.exception.type_error.304] cannot use at() with null", json::type_error&); - CHECK_THROWS_WITH_AS(j_nonobject_const.at(std::string_view(std::string_view("foo"))), "[json.exception.type_error.304] cannot use at() with null", json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject.at(std::string_view(std::string_view("foo"))), "[json.exception.type_error.304] cannot use at() with null", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject_const.at(std::string_view(std::string_view("foo"))), "[json.exception.type_error.304] cannot use at() with null", typename Json::type_error&); #endif } SECTION("boolean") { - json j_nonobject(json::value_t::boolean); - const json j_nonobject_const(j_nonobject); - CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with boolean", json::type_error&); - CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with boolean", json::type_error&); + Json j_nonobject(Json::value_t::boolean); + const Json j_nonobject_const(j_nonobject); + CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with boolean", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with boolean", typename Json::type_error&); #ifdef JSON_HAS_CPP_17 - CHECK_THROWS_WITH_AS(j_nonobject.at(std::string_view("foo")), "[json.exception.type_error.304] cannot use at() with boolean", json::type_error&); - CHECK_THROWS_WITH_AS(j_nonobject_const.at(std::string_view("foo")), "[json.exception.type_error.304] cannot use at() with boolean", json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject.at(std::string_view("foo")), "[json.exception.type_error.304] cannot use at() with boolean", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject_const.at(std::string_view("foo")), "[json.exception.type_error.304] cannot use at() with boolean", typename Json::type_error&); #endif } SECTION("string") { - json j_nonobject(json::value_t::string); - const json j_nonobject_const(j_nonobject); - CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with string", json::type_error&); - CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with string", json::type_error&); + Json j_nonobject(Json::value_t::string); + const Json j_nonobject_const(j_nonobject); + CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with string", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with string", typename Json::type_error&); #ifdef JSON_HAS_CPP_17 - CHECK_THROWS_WITH_AS(j_nonobject.at(std::string_view("foo")), "[json.exception.type_error.304] cannot use at() with string", json::type_error&); - CHECK_THROWS_WITH_AS(j_nonobject_const.at(std::string_view("foo")), "[json.exception.type_error.304] cannot use at() with string", json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject.at(std::string_view("foo")), "[json.exception.type_error.304] cannot use at() with string", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject_const.at(std::string_view("foo")), "[json.exception.type_error.304] cannot use at() with string", typename Json::type_error&); #endif } SECTION("array") { - json j_nonobject(json::value_t::array); - const json j_nonobject_const(j_nonobject); - CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with array", json::type_error&); - CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with array", json::type_error&); + Json j_nonobject(Json::value_t::array); + const Json j_nonobject_const(j_nonobject); + CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with array", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with array", typename Json::type_error&); #ifdef JSON_HAS_CPP_17 - CHECK_THROWS_WITH_AS(j_nonobject.at(std::string_view("foo")), "[json.exception.type_error.304] cannot use at() with array", json::type_error&); - CHECK_THROWS_WITH_AS(j_nonobject_const.at(std::string_view("foo")), "[json.exception.type_error.304] cannot use at() with array", json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject.at(std::string_view("foo")), "[json.exception.type_error.304] cannot use at() with array", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject_const.at(std::string_view("foo")), "[json.exception.type_error.304] cannot use at() with array", typename Json::type_error&); #endif } SECTION("number (integer)") { - json j_nonobject(json::value_t::number_integer); - const json j_nonobject_const(j_nonobject); - CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with number", json::type_error&); - CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with number", json::type_error&); + Json j_nonobject(Json::value_t::number_integer); + const Json j_nonobject_const(j_nonobject); + CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with number", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with number", typename Json::type_error&); #ifdef JSON_HAS_CPP_17 - CHECK_THROWS_WITH_AS(j_nonobject.at(std::string_view("foo")), "[json.exception.type_error.304] cannot use at() with number", json::type_error&); - CHECK_THROWS_WITH_AS(j_nonobject_const.at(std::string_view("foo")), "[json.exception.type_error.304] cannot use at() with number", json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject.at(std::string_view("foo")), "[json.exception.type_error.304] cannot use at() with number", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject_const.at(std::string_view("foo")), "[json.exception.type_error.304] cannot use at() with number", typename Json::type_error&); #endif } SECTION("number (unsigned)") { - json j_nonobject(json::value_t::number_unsigned); - const json j_nonobject_const(j_nonobject); - CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with number", json::type_error&); - CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with number", json::type_error&); + Json j_nonobject(Json::value_t::number_unsigned); + const Json j_nonobject_const(j_nonobject); + CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with number", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with number", typename Json::type_error&); #ifdef JSON_HAS_CPP_17 - CHECK_THROWS_WITH_AS(j_nonobject.at(std::string_view("foo")), "[json.exception.type_error.304] cannot use at() with number", json::type_error&); - CHECK_THROWS_WITH_AS(j_nonobject_const.at(std::string_view("foo")), "[json.exception.type_error.304] cannot use at() with number", json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject.at(std::string_view("foo")), "[json.exception.type_error.304] cannot use at() with number", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject_const.at(std::string_view("foo")), "[json.exception.type_error.304] cannot use at() with number", typename Json::type_error&); #endif } SECTION("number (floating-point)") { - json j_nonobject(json::value_t::number_float); - const json j_nonobject_const(j_nonobject); - CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with number", json::type_error&); - CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with number", json::type_error&); + Json j_nonobject(Json::value_t::number_float); + const Json j_nonobject_const(j_nonobject); + CHECK_THROWS_WITH_AS(j_nonobject.at("foo"), "[json.exception.type_error.304] cannot use at() with number", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject_const.at("foo"), "[json.exception.type_error.304] cannot use at() with number", typename Json::type_error&); #ifdef JSON_HAS_CPP_17 - CHECK_THROWS_WITH_AS(j_nonobject.at(std::string_view("foo")), "[json.exception.type_error.304] cannot use at() with number", json::type_error&); - CHECK_THROWS_WITH_AS(j_nonobject_const.at(std::string_view("foo")), "[json.exception.type_error.304] cannot use at() with number", json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject.at(std::string_view("foo")), "[json.exception.type_error.304] cannot use at() with number", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject_const.at(std::string_view("foo")), "[json.exception.type_error.304] cannot use at() with number", typename Json::type_error&); #endif } } @@ -199,14 +198,14 @@ TEST_CASE("element access 2") CHECK(j.value("integer", 1.0) == Approx(1)); CHECK(j.value("unsigned", 2) == 1u); CHECK(j.value("unsigned", 1.0) == Approx(1u)); - CHECK(j.value("null", json(1)) == json()); + CHECK(j.value("null", Json(1)) == Json()); CHECK(j.value("boolean", false) == true); CHECK(j.value("string", "bar") == "hello world"); CHECK(j.value("string", std::string("bar")) == "hello world"); CHECK(j.value("floating", 12.34) == Approx(42.23)); CHECK(j.value("floating", 12) == 42); - CHECK(j.value("object", json({{"foo", "bar"}})) == json::object()); - CHECK(j.value("array", json({10, 100})) == json({1, 2, 3})); + CHECK(j.value("object", Json({{"foo", "bar"}})) == Json::object()); + CHECK(j.value("array", Json({10, 100})) == Json({1, 2, 3})); CHECK(j_const.value("integer", 2) == 1); CHECK(j_const.value("integer", 1.0) == Approx(1)); @@ -217,22 +216,22 @@ TEST_CASE("element access 2") CHECK(j_const.value("string", std::string("bar")) == "hello world"); CHECK(j_const.value("floating", 12.34) == Approx(42.23)); CHECK(j_const.value("floating", 12) == 42); - CHECK(j_const.value("object", json({{"foo", "bar"}})) == json::object()); - CHECK(j_const.value("array", json({10, 100})) == json({1, 2, 3})); + CHECK(j_const.value("object", Json({{"foo", "bar"}})) == Json::object()); + CHECK(j_const.value("array", Json({10, 100})) == Json({1, 2, 3})); #ifdef JSON_HAS_CPP_17 CHECK(j.value(std::string_view("integer"), 2) == 1); CHECK(j.value(std::string_view("integer"), 1.0) == Approx(1)); CHECK(j.value(std::string_view("unsigned"), 2) == 1u); CHECK(j.value(std::string_view("unsigned"), 1.0) == Approx(1u)); - CHECK(j.value(std::string_view("null"), json(1)) == json()); + CHECK(j.value(std::string_view("null"), Json(1)) == Json()); CHECK(j.value(std::string_view("boolean"), false) == true); CHECK(j.value(std::string_view("string"), "bar") == "hello world"); CHECK(j.value(std::string_view("string"), std::string("bar")) == "hello world"); CHECK(j.value(std::string_view("floating"), 12.34) == Approx(42.23)); CHECK(j.value(std::string_view("floating"), 12) == 42); - CHECK(j.value(std::string_view("object"), json({{"foo", "bar"}})) == json::object()); - CHECK(j.value(std::string_view("array"), json({10, 100})) == json({1, 2, 3})); + CHECK(j.value(std::string_view("object"), Json({{"foo", "bar"}})) == Json::object()); + CHECK(j.value(std::string_view("array"), Json({10, 100})) == Json({1, 2, 3})); CHECK(j_const.value(std::string_view("integer"), 2) == 1); CHECK(j_const.value(std::string_view("integer"), 1.0) == Approx(1)); @@ -243,8 +242,8 @@ TEST_CASE("element access 2") CHECK(j_const.value(std::string_view("string"), std::string("bar")) == "hello world"); CHECK(j_const.value(std::string_view("floating"), 12.34) == Approx(42.23)); CHECK(j_const.value(std::string_view("floating"), 12) == 42); - CHECK(j_const.value(std::string_view("object"), json({{"foo", "bar"}})) == json::object()); - CHECK(j_const.value(std::string_view("array"), json({10, 100})) == json({1, 2, 3})); + CHECK(j_const.value(std::string_view("object"), Json({{"foo", "bar"}})) == Json::object()); + CHECK(j_const.value(std::string_view("array"), Json({10, 100})) == Json({1, 2, 3})); #endif } @@ -255,16 +254,16 @@ TEST_CASE("element access 2") CHECK(j.value("_", false) == false); CHECK(j.value("_", "bar") == "bar"); CHECK(j.value("_", 12.34) == Approx(12.34)); - CHECK(j.value("_", json({{"foo", "bar"}})) == json({{"foo", "bar"}})); - CHECK(j.value("_", json({10, 100})) == json({10, 100})); + CHECK(j.value("_", Json({{"foo", "bar"}})) == Json({{"foo", "bar"}})); + CHECK(j.value("_", Json({10, 100})) == Json({10, 100})); CHECK(j_const.value("_", 2) == 2); CHECK(j_const.value("_", 2u) == 2u); CHECK(j_const.value("_", false) == false); CHECK(j_const.value("_", "bar") == "bar"); CHECK(j_const.value("_", 12.34) == Approx(12.34)); - CHECK(j_const.value("_", json({{"foo", "bar"}})) == json({{"foo", "bar"}})); - CHECK(j_const.value("_", json({10, 100})) == json({10, 100})); + CHECK(j_const.value("_", Json({{"foo", "bar"}})) == Json({{"foo", "bar"}})); + CHECK(j_const.value("_", Json({10, 100})) == Json({10, 100})); #ifdef JSON_HAS_CPP_17 CHECK(j.value(std::string_view("_"), 2) == 2); @@ -272,16 +271,16 @@ TEST_CASE("element access 2") CHECK(j.value(std::string_view("_"), false) == false); CHECK(j.value(std::string_view("_"), "bar") == "bar"); CHECK(j.value(std::string_view("_"), 12.34) == Approx(12.34)); - CHECK(j.value(std::string_view("_"), json({{"foo", "bar"}})) == json({{"foo", "bar"}})); - CHECK(j.value(std::string_view("_"), json({10, 100})) == json({10, 100})); + CHECK(j.value(std::string_view("_"), Json({{"foo", "bar"}})) == Json({{"foo", "bar"}})); + CHECK(j.value(std::string_view("_"), Json({10, 100})) == Json({10, 100})); CHECK(j_const.value(std::string_view("_"), 2) == 2); CHECK(j_const.value(std::string_view("_"), 2u) == 2u); CHECK(j_const.value(std::string_view("_"), false) == false); CHECK(j_const.value(std::string_view("_"), "bar") == "bar"); CHECK(j_const.value(std::string_view("_"), 12.34) == Approx(12.34)); - CHECK(j_const.value(std::string_view("_"), json({{"foo", "bar"}})) == json({{"foo", "bar"}})); - CHECK(j_const.value(std::string_view("_"), json({10, 100})) == json({10, 100})); + CHECK(j_const.value(std::string_view("_"), Json({{"foo", "bar"}})) == Json({{"foo", "bar"}})); + CHECK(j_const.value(std::string_view("_"), Json({10, 100})) == Json({10, 100})); #endif } @@ -289,92 +288,92 @@ TEST_CASE("element access 2") { SECTION("null") { - json j_nonobject(json::value_t::null); - const json j_nonobject_const(json::value_t::null); - CHECK_THROWS_WITH_AS(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with null", json::type_error&); - CHECK_THROWS_WITH_AS(j_nonobject_const.value("foo", 1), "[json.exception.type_error.306] cannot use value() with null", json::type_error&); + Json j_nonobject(Json::value_t::null); + const Json j_nonobject_const(Json::value_t::null); + CHECK_THROWS_WITH_AS(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with null", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject_const.value("foo", 1), "[json.exception.type_error.306] cannot use value() with null", typename Json::type_error&); #ifdef JSON_HAS_CPP_17 - CHECK_THROWS_WITH_AS(j_nonobject.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with null", json::type_error&); - CHECK_THROWS_WITH_AS(j_nonobject_const.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with null", json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with null", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject_const.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with null", typename Json::type_error&); #endif } SECTION("boolean") { - json j_nonobject(json::value_t::boolean); - const json j_nonobject_const(json::value_t::boolean); - CHECK_THROWS_WITH_AS(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with boolean", json::type_error&); - CHECK_THROWS_WITH_AS(j_nonobject_const.value("foo", 1), "[json.exception.type_error.306] cannot use value() with boolean", json::type_error&); + Json j_nonobject(Json::value_t::boolean); + const Json j_nonobject_const(Json::value_t::boolean); + CHECK_THROWS_WITH_AS(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with boolean", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject_const.value("foo", 1), "[json.exception.type_error.306] cannot use value() with boolean", typename Json::type_error&); #ifdef JSON_HAS_CPP_17 - CHECK_THROWS_WITH_AS(j_nonobject.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with boolean", json::type_error&); - CHECK_THROWS_WITH_AS(j_nonobject_const.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with boolean", json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with boolean", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject_const.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with boolean", typename Json::type_error&); #endif } SECTION("string") { - json j_nonobject(json::value_t::string); - const json j_nonobject_const(json::value_t::string); - CHECK_THROWS_WITH_AS(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with string", json::type_error&); - CHECK_THROWS_WITH_AS(j_nonobject_const.value("foo", 1), "[json.exception.type_error.306] cannot use value() with string", json::type_error&); + Json j_nonobject(Json::value_t::string); + const Json j_nonobject_const(Json::value_t::string); + CHECK_THROWS_WITH_AS(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with string", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject_const.value("foo", 1), "[json.exception.type_error.306] cannot use value() with string", typename Json::type_error&); #ifdef JSON_HAS_CPP_17 - CHECK_THROWS_WITH_AS(j_nonobject.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with string", json::type_error&); - CHECK_THROWS_WITH_AS(j_nonobject_const.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with string", json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with string", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject_const.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with string", typename Json::type_error&); #endif } SECTION("array") { - json j_nonobject(json::value_t::array); - const json j_nonobject_const(json::value_t::array); - CHECK_THROWS_WITH_AS(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with array", json::type_error&); - CHECK_THROWS_WITH_AS(j_nonobject_const.value("foo", 1), "[json.exception.type_error.306] cannot use value() with array", json::type_error&); + Json j_nonobject(Json::value_t::array); + const Json j_nonobject_const(Json::value_t::array); + CHECK_THROWS_WITH_AS(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with array", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject_const.value("foo", 1), "[json.exception.type_error.306] cannot use value() with array", typename Json::type_error&); #ifdef JSON_HAS_CPP_17 - CHECK_THROWS_WITH_AS(j_nonobject.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with array", json::type_error&); - CHECK_THROWS_WITH_AS(j_nonobject_const.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with array", json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with array", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject_const.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with array", typename Json::type_error&); #endif } SECTION("number (integer)") { - json j_nonobject(json::value_t::number_integer); - const json j_nonobject_const(json::value_t::number_integer); - CHECK_THROWS_WITH_AS(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with number", json::type_error&); - CHECK_THROWS_WITH_AS(j_nonobject_const.value("foo", 1), "[json.exception.type_error.306] cannot use value() with number", json::type_error&); + Json j_nonobject(Json::value_t::number_integer); + const Json j_nonobject_const(Json::value_t::number_integer); + CHECK_THROWS_WITH_AS(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with number", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject_const.value("foo", 1), "[json.exception.type_error.306] cannot use value() with number", typename Json::type_error&); #ifdef JSON_HAS_CPP_17 - CHECK_THROWS_WITH_AS(j_nonobject.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with number", json::type_error&); - CHECK_THROWS_WITH_AS(j_nonobject_const.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with number", json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with number", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject_const.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with number", typename Json::type_error&); #endif } SECTION("number (unsigned)") { - json j_nonobject(json::value_t::number_unsigned); - const json j_nonobject_const(json::value_t::number_unsigned); - CHECK_THROWS_WITH_AS(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with number", json::type_error&); - CHECK_THROWS_WITH_AS(j_nonobject_const.value("foo", 1), "[json.exception.type_error.306] cannot use value() with number", json::type_error&); + Json j_nonobject(Json::value_t::number_unsigned); + const Json j_nonobject_const(Json::value_t::number_unsigned); + CHECK_THROWS_WITH_AS(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with number", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject_const.value("foo", 1), "[json.exception.type_error.306] cannot use value() with number", typename Json::type_error&); #ifdef JSON_HAS_CPP_17 - CHECK_THROWS_WITH_AS(j_nonobject.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with number", json::type_error&); - CHECK_THROWS_WITH_AS(j_nonobject_const.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with number", json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with number", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject_const.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with number", typename Json::type_error&); #endif } SECTION("number (floating-point)") { - json j_nonobject(json::value_t::number_float); - const json j_nonobject_const(json::value_t::number_float); - CHECK_THROWS_WITH_AS(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with number", json::type_error&); - CHECK_THROWS_WITH_AS(j_nonobject_const.value("foo", 1), "[json.exception.type_error.306] cannot use value() with number", json::type_error&); + Json j_nonobject(Json::value_t::number_float); + const Json j_nonobject_const(Json::value_t::number_float); + CHECK_THROWS_WITH_AS(j_nonobject.value("foo", 1), "[json.exception.type_error.306] cannot use value() with number", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject_const.value("foo", 1), "[json.exception.type_error.306] cannot use value() with number", typename Json::type_error&); #ifdef JSON_HAS_CPP_17 - CHECK_THROWS_WITH_AS(j_nonobject.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with number", json::type_error&); - CHECK_THROWS_WITH_AS(j_nonobject_const.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with number", json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with number", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject_const.value(std::string_view("foo"), 1), "[json.exception.type_error.306] cannot use value() with number", typename Json::type_error&); #endif } } @@ -388,14 +387,14 @@ TEST_CASE("element access 2") CHECK(j.value("/integer"_json_pointer, 1.0) == Approx(1)); CHECK(j.value("/unsigned"_json_pointer, 2) == 1u); CHECK(j.value("/unsigned"_json_pointer, 1.0) == Approx(1u)); - CHECK(j.value("/null"_json_pointer, json(1)) == json()); + CHECK(j.value("/null"_json_pointer, Json(1)) == Json()); CHECK(j.value("/boolean"_json_pointer, false) == true); CHECK(j.value("/string"_json_pointer, "bar") == "hello world"); CHECK(j.value("/string"_json_pointer, std::string("bar")) == "hello world"); CHECK(j.value("/floating"_json_pointer, 12.34) == Approx(42.23)); CHECK(j.value("/floating"_json_pointer, 12) == 42); - CHECK(j.value("/object"_json_pointer, json({{"foo", "bar"}})) == json::object()); - CHECK(j.value("/array"_json_pointer, json({10, 100})) == json({1, 2, 3})); + CHECK(j.value("/object"_json_pointer, Json({{"foo", "bar"}})) == Json::object()); + CHECK(j.value("/array"_json_pointer, Json({10, 100})) == Json({1, 2, 3})); CHECK(j_const.value("/integer"_json_pointer, 2) == 1); CHECK(j_const.value("/integer"_json_pointer, 1.0) == Approx(1)); @@ -406,66 +405,66 @@ TEST_CASE("element access 2") CHECK(j_const.value("/string"_json_pointer, std::string("bar")) == "hello world"); CHECK(j_const.value("/floating"_json_pointer, 12.34) == Approx(42.23)); CHECK(j_const.value("/floating"_json_pointer, 12) == 42); - CHECK(j_const.value("/object"_json_pointer, json({{"foo", "bar"}})) == json::object()); - CHECK(j_const.value("/array"_json_pointer, json({10, 100})) == json({1, 2, 3})); + CHECK(j_const.value("/object"_json_pointer, Json({{"foo", "bar"}})) == Json::object()); + CHECK(j_const.value("/array"_json_pointer, Json({10, 100})) == Json({1, 2, 3})); } SECTION("access on non-object type") { SECTION("null") { - json j_nonobject(json::value_t::null); - const json j_nonobject_const(json::value_t::null); - CHECK_THROWS_WITH_AS(j_nonobject.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with null", json::type_error&); - CHECK_THROWS_WITH_AS(j_nonobject_const.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with null", json::type_error&); + Json j_nonobject(Json::value_t::null); + const Json j_nonobject_const(Json::value_t::null); + CHECK_THROWS_WITH_AS(j_nonobject.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with null", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject_const.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with null", typename Json::type_error&); } SECTION("boolean") { - json j_nonobject(json::value_t::boolean); - const json j_nonobject_const(json::value_t::boolean); - CHECK_THROWS_WITH_AS(j_nonobject.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with boolean", json::type_error&); - CHECK_THROWS_WITH_AS(j_nonobject_const.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with boolean", json::type_error&); + Json j_nonobject(Json::value_t::boolean); + const Json j_nonobject_const(Json::value_t::boolean); + CHECK_THROWS_WITH_AS(j_nonobject.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with boolean", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject_const.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with boolean", typename Json::type_error&); } SECTION("string") { - json j_nonobject(json::value_t::string); - const json j_nonobject_const(json::value_t::string); - CHECK_THROWS_WITH_AS(j_nonobject.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with string", json::type_error&); - CHECK_THROWS_WITH_AS(j_nonobject_const.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with string", json::type_error&); + Json j_nonobject(Json::value_t::string); + const Json j_nonobject_const(Json::value_t::string); + CHECK_THROWS_WITH_AS(j_nonobject.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with string", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject_const.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with string", typename Json::type_error&); } SECTION("array") { - json j_nonobject(json::value_t::array); - const json j_nonobject_const(json::value_t::array); - CHECK_THROWS_WITH_AS(j_nonobject.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with array", json::type_error&); - CHECK_THROWS_WITH_AS(j_nonobject_const.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with array", json::type_error&); + Json j_nonobject(Json::value_t::array); + const Json j_nonobject_const(Json::value_t::array); + CHECK_THROWS_WITH_AS(j_nonobject.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with array", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject_const.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with array", typename Json::type_error&); } SECTION("number (integer)") { - json j_nonobject(json::value_t::number_integer); - const json j_nonobject_const(json::value_t::number_integer); - CHECK_THROWS_WITH_AS(j_nonobject.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with number", json::type_error&); - CHECK_THROWS_WITH_AS(j_nonobject_const.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with number", json::type_error&); + Json j_nonobject(Json::value_t::number_integer); + const Json j_nonobject_const(Json::value_t::number_integer); + CHECK_THROWS_WITH_AS(j_nonobject.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with number", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject_const.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with number", typename Json::type_error&); } SECTION("number (unsigned)") { - json j_nonobject(json::value_t::number_unsigned); - const json j_nonobject_const(json::value_t::number_unsigned); - CHECK_THROWS_WITH_AS(j_nonobject.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with number", json::type_error&); - CHECK_THROWS_WITH_AS(j_nonobject_const.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with number", json::type_error&); + Json j_nonobject(Json::value_t::number_unsigned); + const Json j_nonobject_const(Json::value_t::number_unsigned); + CHECK_THROWS_WITH_AS(j_nonobject.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with number", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject_const.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with number", typename Json::type_error&); } SECTION("number (floating-point)") { - json j_nonobject(json::value_t::number_float); - const json j_nonobject_const(json::value_t::number_float); - CHECK_THROWS_WITH_AS(j_nonobject.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with number", json::type_error&); - CHECK_THROWS_WITH_AS(j_nonobject_const.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with number", json::type_error&); + Json j_nonobject(Json::value_t::number_float); + const Json j_nonobject_const(Json::value_t::number_float); + CHECK_THROWS_WITH_AS(j_nonobject.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with number", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject_const.value("/foo"_json_pointer, 1), "[json.exception.type_error.306] cannot use value() with number", typename Json::type_error&); } } } @@ -474,7 +473,7 @@ TEST_CASE("element access 2") SECTION("non-const operator[]") { { - json j_null; + Json j_null; CHECK(j_null.is_null()); j_null["key"] = 1; CHECK(j_null.is_object()); @@ -485,7 +484,7 @@ TEST_CASE("element access 2") #ifdef JSON_HAS_CPP_17 { std::string_view key = "key"; - json j_null; + Json j_null; CHECK(j_null.is_null()); j_null[key] = 1; CHECK(j_null.is_object()); @@ -498,110 +497,122 @@ TEST_CASE("element access 2") SECTION("front and back") { - // "array" is the smallest key - CHECK(j.front() == json({1, 2, 3})); - CHECK(j_const.front() == json({1, 2, 3})); - // "unsigned" is the largest key - CHECK(j.back() == json(1u)); - CHECK(j_const.back() == json(1u)); + if (std::is_same::value) + { + // "integer" is the first key + CHECK(j.front() == Json(1)); + CHECK(j_const.front() == Json(1)); + // "array" is last key + CHECK(j.back() == Json({1, 2, 3})); + CHECK(j_const.back() == Json({1, 2, 3})); + } + else + { + // "array" is the smallest key + CHECK(j.front() == Json({1, 2, 3})); + CHECK(j_const.front() == Json({1, 2, 3})); + // "unsigned" is the largest key + CHECK(j.back() == Json(1u)); + CHECK(j_const.back() == Json(1u)); + } } SECTION("access specified element") { SECTION("access within bounds") { - CHECK(j["integer"] == json(1)); - CHECK(j[json::object_t::key_type("integer")] == j["integer"]); + CHECK(j["integer"] == Json(1)); + CHECK(j[typename Json::object_t::key_type("integer")] == j["integer"]); - CHECK(j["unsigned"] == json(1u)); - CHECK(j[json::object_t::key_type("unsigned")] == j["unsigned"]); + CHECK(j["unsigned"] == Json(1u)); + CHECK(j[typename Json::object_t::key_type("unsigned")] == j["unsigned"]); - CHECK(j["boolean"] == json(true)); - CHECK(j[json::object_t::key_type("boolean")] == j["boolean"]); + CHECK(j["boolean"] == Json(true)); + CHECK(j[typename Json::object_t::key_type("boolean")] == j["boolean"]); - CHECK(j["null"] == json(nullptr)); - CHECK(j[json::object_t::key_type("null")] == j["null"]); + CHECK(j["null"] == Json(nullptr)); + CHECK(j[typename Json::object_t::key_type("null")] == j["null"]); - CHECK(j["string"] == json("hello world")); - CHECK(j[json::object_t::key_type("string")] == j["string"]); + CHECK(j["string"] == Json("hello world")); + CHECK(j[typename Json::object_t::key_type("string")] == j["string"]); - CHECK(j["floating"] == json(42.23)); - CHECK(j[json::object_t::key_type("floating")] == j["floating"]); + CHECK(j["floating"] == Json(42.23)); + CHECK(j[typename Json::object_t::key_type("floating")] == j["floating"]); - CHECK(j["object"] == json::object()); - CHECK(j[json::object_t::key_type("object")] == j["object"]); + CHECK(j["object"] == Json::object()); + CHECK(j[typename Json::object_t::key_type("object")] == j["object"]); - CHECK(j["array"] == json({1, 2, 3})); - CHECK(j[json::object_t::key_type("array")] == j["array"]); + CHECK(j["array"] == Json({1, 2, 3})); + CHECK(j[typename Json::object_t::key_type("array")] == j["array"]); - CHECK(j_const["integer"] == json(1)); - CHECK(j_const[json::object_t::key_type("integer")] == j["integer"]); + CHECK(j_const["integer"] == Json(1)); + CHECK(j_const[typename Json::object_t::key_type("integer")] == j["integer"]); - CHECK(j_const["boolean"] == json(true)); - CHECK(j_const[json::object_t::key_type("boolean")] == j["boolean"]); + CHECK(j_const["boolean"] == Json(true)); + CHECK(j_const[typename Json::object_t::key_type("boolean")] == j["boolean"]); - CHECK(j_const["null"] == json(nullptr)); - CHECK(j_const[json::object_t::key_type("null")] == j["null"]); + CHECK(j_const["null"] == Json(nullptr)); + CHECK(j_const[typename Json::object_t::key_type("null")] == j["null"]); - CHECK(j_const["string"] == json("hello world")); - CHECK(j_const[json::object_t::key_type("string")] == j["string"]); + CHECK(j_const["string"] == Json("hello world")); + CHECK(j_const[typename Json::object_t::key_type("string")] == j["string"]); - CHECK(j_const["floating"] == json(42.23)); - CHECK(j_const[json::object_t::key_type("floating")] == j["floating"]); + CHECK(j_const["floating"] == Json(42.23)); + CHECK(j_const[typename Json::object_t::key_type("floating")] == j["floating"]); - CHECK(j_const["object"] == json::object()); - CHECK(j_const[json::object_t::key_type("object")] == j["object"]); + CHECK(j_const["object"] == Json::object()); + CHECK(j_const[typename Json::object_t::key_type("object")] == j["object"]); - CHECK(j_const["array"] == json({1, 2, 3})); - CHECK(j_const[json::object_t::key_type("array")] == j["array"]); + CHECK(j_const["array"] == Json({1, 2, 3})); + CHECK(j_const[typename Json::object_t::key_type("array")] == j["array"]); } #ifdef JSON_HAS_CPP_17 SECTION("access within bounds (string_view)") { - CHECK(j["integer"] == json(1)); + CHECK(j["integer"] == Json(1)); CHECK(j[std::string_view("integer")] == j["integer"]); - CHECK(j["unsigned"] == json(1u)); + CHECK(j["unsigned"] == Json(1u)); CHECK(j[std::string_view("unsigned")] == j["unsigned"]); - CHECK(j["boolean"] == json(true)); + CHECK(j["boolean"] == Json(true)); CHECK(j[std::string_view("boolean")] == j["boolean"]); - CHECK(j["null"] == json(nullptr)); + CHECK(j["null"] == Json(nullptr)); CHECK(j[std::string_view("null")] == j["null"]); - CHECK(j["string"] == json("hello world")); + CHECK(j["string"] == Json("hello world")); CHECK(j[std::string_view("string")] == j["string"]); - CHECK(j["floating"] == json(42.23)); + CHECK(j["floating"] == Json(42.23)); CHECK(j[std::string_view("floating")] == j["floating"]); - CHECK(j["object"] == json::object()); + CHECK(j["object"] == Json::object()); CHECK(j[std::string_view("object")] == j["object"]); - CHECK(j["array"] == json({1, 2, 3})); + CHECK(j["array"] == Json({1, 2, 3})); CHECK(j[std::string_view("array")] == j["array"]); - CHECK(j_const["integer"] == json(1)); + CHECK(j_const["integer"] == Json(1)); CHECK(j_const[std::string_view("integer")] == j["integer"]); - CHECK(j_const["boolean"] == json(true)); + CHECK(j_const["boolean"] == Json(true)); CHECK(j_const[std::string_view("boolean")] == j["boolean"]); - CHECK(j_const["null"] == json(nullptr)); + CHECK(j_const["null"] == Json(nullptr)); CHECK(j_const[std::string_view("null")] == j["null"]); - CHECK(j_const["string"] == json("hello world")); + CHECK(j_const["string"] == Json("hello world")); CHECK(j_const[std::string_view("string")] == j["string"]); - CHECK(j_const["floating"] == json(42.23)); + CHECK(j_const["floating"] == Json(42.23)); CHECK(j_const[std::string_view("floating")] == j["floating"]); - CHECK(j_const["object"] == json::object()); + CHECK(j_const["object"] == Json::object()); CHECK(j_const[std::string_view("object")] == j["object"]); - CHECK(j_const["array"] == json({1, 2, 3})); + CHECK(j_const["array"] == Json({1, 2, 3})); CHECK(j_const[std::string_view("array")] == j["array"]); } #endif @@ -610,131 +621,131 @@ TEST_CASE("element access 2") { SECTION("null") { - json j_nonobject(json::value_t::null); - json j_nonobject2(json::value_t::null); - const json j_const_nonobject(j_nonobject); + Json j_nonobject(Json::value_t::null); + Json j_nonobject2(Json::value_t::null); + const Json j_const_nonobject(j_nonobject); CHECK_NOTHROW(j_nonobject["foo"]); - CHECK_NOTHROW(j_nonobject2[json::object_t::key_type("foo")]); - CHECK_THROWS_WITH_AS(j_const_nonobject["foo"], "[json.exception.type_error.305] cannot use operator[] with a string argument with null", json::type_error&); - CHECK_THROWS_WITH_AS(j_const_nonobject[json::object_t::key_type("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with null", json::type_error&); + CHECK_NOTHROW(j_nonobject2[typename Json::object_t::key_type("foo")]); + CHECK_THROWS_WITH_AS(j_const_nonobject["foo"], "[json.exception.type_error.305] cannot use operator[] with a string argument with null", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_const_nonobject[typename Json::object_t::key_type("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with null", typename Json::type_error&); #ifdef JSON_HAS_CPP_17 CHECK_NOTHROW(j_nonobject2[std::string_view("foo")]); - CHECK_THROWS_WITH_AS(j_const_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with null", json::type_error&); + CHECK_THROWS_WITH_AS(j_const_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with null", typename Json::type_error&); #endif } SECTION("boolean") { - json j_nonobject(json::value_t::boolean); - const json j_const_nonobject(j_nonobject); + Json j_nonobject(Json::value_t::boolean); + const Json j_const_nonobject(j_nonobject); CHECK_THROWS_WITH_AS(j_nonobject["foo"], - "[json.exception.type_error.305] cannot use operator[] with a string argument with boolean", json::type_error&); - CHECK_THROWS_WITH_AS(j_nonobject[json::object_t::key_type("foo")], - "[json.exception.type_error.305] cannot use operator[] with a string argument with boolean", json::type_error&); + "[json.exception.type_error.305] cannot use operator[] with a string argument with boolean", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject[typename Json::object_t::key_type("foo")], + "[json.exception.type_error.305] cannot use operator[] with a string argument with boolean", typename Json::type_error&); CHECK_THROWS_WITH_AS(j_const_nonobject["foo"], - "[json.exception.type_error.305] cannot use operator[] with a string argument with boolean", json::type_error&); - CHECK_THROWS_WITH_AS(j_const_nonobject[json::object_t::key_type("foo")], - "[json.exception.type_error.305] cannot use operator[] with a string argument with boolean", json::type_error&); + "[json.exception.type_error.305] cannot use operator[] with a string argument with boolean", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_const_nonobject[typename Json::object_t::key_type("foo")], + "[json.exception.type_error.305] cannot use operator[] with a string argument with boolean", typename Json::type_error&); #ifdef JSON_HAS_CPP_17 - CHECK_THROWS_WITH_AS(j_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with boolean", json::type_error&); - CHECK_THROWS_WITH_AS(j_const_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with boolean", json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with boolean", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_const_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with boolean", typename Json::type_error&); #endif } SECTION("string") { - json j_nonobject(json::value_t::string); - const json j_const_nonobject(j_nonobject); + Json j_nonobject(Json::value_t::string); + const Json j_const_nonobject(j_nonobject); CHECK_THROWS_WITH_AS(j_nonobject["foo"], - "[json.exception.type_error.305] cannot use operator[] with a string argument with string", json::type_error&); - CHECK_THROWS_WITH_AS(j_nonobject[json::object_t::key_type("foo")], - "[json.exception.type_error.305] cannot use operator[] with a string argument with string", json::type_error&); + "[json.exception.type_error.305] cannot use operator[] with a string argument with string", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject[typename Json::object_t::key_type("foo")], + "[json.exception.type_error.305] cannot use operator[] with a string argument with string", typename Json::type_error&); CHECK_THROWS_WITH_AS(j_const_nonobject["foo"], - "[json.exception.type_error.305] cannot use operator[] with a string argument with string", json::type_error&); - CHECK_THROWS_WITH_AS(j_const_nonobject[json::object_t::key_type("foo")], - "[json.exception.type_error.305] cannot use operator[] with a string argument with string", json::type_error&); + "[json.exception.type_error.305] cannot use operator[] with a string argument with string", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_const_nonobject[typename Json::object_t::key_type("foo")], + "[json.exception.type_error.305] cannot use operator[] with a string argument with string", typename Json::type_error&); #ifdef JSON_HAS_CPP_17 - CHECK_THROWS_WITH_AS(j_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with string", json::type_error&); - CHECK_THROWS_WITH_AS(j_const_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with string", json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with string", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_const_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with string", typename Json::type_error&); #endif } SECTION("array") { - json j_nonobject(json::value_t::array); - const json j_const_nonobject(j_nonobject); + Json j_nonobject(Json::value_t::array); + const Json j_const_nonobject(j_nonobject); CHECK_THROWS_WITH_AS(j_nonobject["foo"], - "[json.exception.type_error.305] cannot use operator[] with a string argument with array", json::type_error&); - CHECK_THROWS_WITH_AS(j_nonobject[json::object_t::key_type("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with array", json::type_error&); + "[json.exception.type_error.305] cannot use operator[] with a string argument with array", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject[typename Json::object_t::key_type("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with array", typename Json::type_error&); CHECK_THROWS_WITH_AS(j_const_nonobject["foo"], - "[json.exception.type_error.305] cannot use operator[] with a string argument with array", json::type_error&); - CHECK_THROWS_WITH_AS(j_const_nonobject[json::object_t::key_type("foo")], - "[json.exception.type_error.305] cannot use operator[] with a string argument with array", json::type_error&); + "[json.exception.type_error.305] cannot use operator[] with a string argument with array", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_const_nonobject[typename Json::object_t::key_type("foo")], + "[json.exception.type_error.305] cannot use operator[] with a string argument with array", typename Json::type_error&); #ifdef JSON_HAS_CPP_17 - CHECK_THROWS_WITH_AS(j_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with array", json::type_error&); - CHECK_THROWS_WITH_AS(j_const_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with array", json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with array", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_const_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with array", typename Json::type_error&); #endif } SECTION("number (integer)") { - json j_nonobject(json::value_t::number_integer); - const json j_const_nonobject(j_nonobject); + Json j_nonobject(Json::value_t::number_integer); + const Json j_const_nonobject(j_nonobject); CHECK_THROWS_WITH_AS(j_nonobject["foo"], - "[json.exception.type_error.305] cannot use operator[] with a string argument with number", json::type_error&); - CHECK_THROWS_WITH_AS(j_nonobject[json::object_t::key_type("foo")], - "[json.exception.type_error.305] cannot use operator[] with a string argument with number", json::type_error&); + "[json.exception.type_error.305] cannot use operator[] with a string argument with number", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject[typename Json::object_t::key_type("foo")], + "[json.exception.type_error.305] cannot use operator[] with a string argument with number", typename Json::type_error&); CHECK_THROWS_WITH_AS(j_const_nonobject["foo"], - "[json.exception.type_error.305] cannot use operator[] with a string argument with number", json::type_error&); - CHECK_THROWS_WITH_AS(j_const_nonobject[json::object_t::key_type("foo")], - "[json.exception.type_error.305] cannot use operator[] with a string argument with number", json::type_error&); + "[json.exception.type_error.305] cannot use operator[] with a string argument with number", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_const_nonobject[typename Json::object_t::key_type("foo")], + "[json.exception.type_error.305] cannot use operator[] with a string argument with number", typename Json::type_error&); #ifdef JSON_HAS_CPP_17 - CHECK_THROWS_WITH_AS(j_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with number", json::type_error&); - CHECK_THROWS_WITH_AS(j_const_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with number", json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with number", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_const_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with number", typename Json::type_error&); #endif } SECTION("number (unsigned)") { - json j_nonobject(json::value_t::number_unsigned); - const json j_const_nonobject(j_nonobject); + Json j_nonobject(Json::value_t::number_unsigned); + const Json j_const_nonobject(j_nonobject); CHECK_THROWS_WITH_AS(j_nonobject["foo"], - "[json.exception.type_error.305] cannot use operator[] with a string argument with number", json::type_error&); - CHECK_THROWS_WITH_AS(j_nonobject[json::object_t::key_type("foo")], - "[json.exception.type_error.305] cannot use operator[] with a string argument with number", json::type_error&); + "[json.exception.type_error.305] cannot use operator[] with a string argument with number", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject[typename Json::object_t::key_type("foo")], + "[json.exception.type_error.305] cannot use operator[] with a string argument with number", typename Json::type_error&); CHECK_THROWS_WITH_AS(j_const_nonobject["foo"], - "[json.exception.type_error.305] cannot use operator[] with a string argument with number", json::type_error&); - CHECK_THROWS_WITH_AS(j_const_nonobject[json::object_t::key_type("foo")], - "[json.exception.type_error.305] cannot use operator[] with a string argument with number", json::type_error&); + "[json.exception.type_error.305] cannot use operator[] with a string argument with number", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_const_nonobject[typename Json::object_t::key_type("foo")], + "[json.exception.type_error.305] cannot use operator[] with a string argument with number", typename Json::type_error&); #ifdef JSON_HAS_CPP_17 - CHECK_THROWS_WITH_AS(j_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with number", json::type_error&); - CHECK_THROWS_WITH_AS(j_const_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with number", json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with number", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_const_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with number", typename Json::type_error&); #endif } SECTION("number (floating-point)") { - json j_nonobject(json::value_t::number_float); - const json j_const_nonobject(j_nonobject); + Json j_nonobject(Json::value_t::number_float); + const Json j_const_nonobject(j_nonobject); CHECK_THROWS_WITH_AS(j_nonobject["foo"], - "[json.exception.type_error.305] cannot use operator[] with a string argument with number", json::type_error&); - CHECK_THROWS_WITH_AS(j_nonobject[json::object_t::key_type("foo")], - "[json.exception.type_error.305] cannot use operator[] with a string argument with number", json::type_error&); + "[json.exception.type_error.305] cannot use operator[] with a string argument with number", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject[typename Json::object_t::key_type("foo")], + "[json.exception.type_error.305] cannot use operator[] with a string argument with number", typename Json::type_error&); CHECK_THROWS_WITH_AS(j_const_nonobject["foo"], - "[json.exception.type_error.305] cannot use operator[] with a string argument with number", json::type_error&); - CHECK_THROWS_WITH_AS(j_const_nonobject[json::object_t::key_type("foo")], - "[json.exception.type_error.305] cannot use operator[] with a string argument with number", json::type_error&); + "[json.exception.type_error.305] cannot use operator[] with a string argument with number", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_const_nonobject[typename Json::object_t::key_type("foo")], + "[json.exception.type_error.305] cannot use operator[] with a string argument with number", typename Json::type_error&); #ifdef JSON_HAS_CPP_17 - CHECK_THROWS_WITH_AS(j_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with number", json::type_error&); - CHECK_THROWS_WITH_AS(j_const_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with number", json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with number", typename Json::type_error&); + CHECK_THROWS_WITH_AS(j_const_nonobject[std::string_view("foo")], "[json.exception.type_error.305] cannot use operator[] with a string argument with number", typename Json::type_error&); #endif } } @@ -835,31 +846,31 @@ TEST_CASE("element access 2") SECTION("erase(begin())") { { - json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}}; - json::iterator it2 = jobject.erase(jobject.begin()); - CHECK(jobject == json({{"b", 1}, {"c", 17u}})); - CHECK(*it2 == json(1)); + Json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}}; + typename Json::iterator it2 = jobject.erase(jobject.begin()); + CHECK(jobject == Json({{"b", 1}, {"c", 17u}})); + CHECK(*it2 == Json(1)); } { - json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}}; - json::const_iterator it2 = jobject.erase(jobject.cbegin()); - CHECK(jobject == json({{"b", 1}, {"c", 17u}})); - CHECK(*it2 == json(1)); + Json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}}; + typename Json::const_iterator it2 = jobject.erase(jobject.cbegin()); + CHECK(jobject == Json({{"b", 1}, {"c", 17u}})); + CHECK(*it2 == Json(1)); } } SECTION("erase(begin(), end())") { { - json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}}; - json::iterator it2 = jobject.erase(jobject.begin(), jobject.end()); - CHECK(jobject == json::object()); + Json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}}; + typename Json::iterator it2 = jobject.erase(jobject.begin(), jobject.end()); + CHECK(jobject == Json::object()); CHECK(it2 == jobject.end()); } { - json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}}; - json::const_iterator it2 = jobject.erase(jobject.cbegin(), jobject.cend()); - CHECK(jobject == json::object()); + Json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}}; + typename Json::const_iterator it2 = jobject.erase(jobject.cbegin(), jobject.cend()); + CHECK(jobject == Json::object()); CHECK(it2 == jobject.cend()); } } @@ -867,78 +878,78 @@ TEST_CASE("element access 2") SECTION("erase(begin(), begin())") { { - json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}}; - json::iterator it2 = jobject.erase(jobject.begin(), jobject.begin()); - CHECK(jobject == json({{"a", "a"}, {"b", 1}, {"c", 17u}})); - CHECK(*it2 == json("a")); + Json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}}; + typename Json::iterator it2 = jobject.erase(jobject.begin(), jobject.begin()); + CHECK(jobject == Json({{"a", "a"}, {"b", 1}, {"c", 17u}})); + CHECK(*it2 == Json("a")); } { - json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}}; - json::const_iterator it2 = jobject.erase(jobject.cbegin(), jobject.cbegin()); - CHECK(jobject == json({{"a", "a"}, {"b", 1}, {"c", 17u}})); - CHECK(*it2 == json("a")); + Json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}}; + typename Json::const_iterator it2 = jobject.erase(jobject.cbegin(), jobject.cbegin()); + CHECK(jobject == Json({{"a", "a"}, {"b", 1}, {"c", 17u}})); + CHECK(*it2 == Json("a")); } } SECTION("erase at offset") { { - json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}}; - json::iterator it = jobject.find("b"); - json::iterator it2 = jobject.erase(it); - CHECK(jobject == json({{"a", "a"}, {"c", 17u}})); - CHECK(*it2 == json(17)); + Json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}}; + typename Json::iterator it = jobject.find("b"); + typename Json::iterator it2 = jobject.erase(it); + CHECK(jobject == Json({{"a", "a"}, {"c", 17u}})); + CHECK(*it2 == Json(17)); } { - json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}}; - json::const_iterator it = jobject.find("b"); - json::const_iterator it2 = jobject.erase(it); - CHECK(jobject == json({{"a", "a"}, {"c", 17u}})); - CHECK(*it2 == json(17)); + Json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}}; + typename Json::const_iterator it = jobject.find("b"); + typename Json::const_iterator it2 = jobject.erase(it); + CHECK(jobject == Json({{"a", "a"}, {"c", 17u}})); + CHECK(*it2 == Json(17)); } } SECTION("erase subrange") { { - json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}}; - json::iterator it2 = jobject.erase(jobject.find("b"), jobject.find("e")); - CHECK(jobject == json({{"a", "a"}, {"e", true}})); - CHECK(*it2 == json(true)); + Json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}}; + typename Json::iterator it2 = jobject.erase(jobject.find("b"), jobject.find("e")); + CHECK(jobject == Json({{"a", "a"}, {"e", true}})); + CHECK(*it2 == Json(true)); } { - json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}}; - json::const_iterator it2 = jobject.erase(jobject.find("b"), jobject.find("e")); - CHECK(jobject == json({{"a", "a"}, {"e", true}})); - CHECK(*it2 == json(true)); + Json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}}; + typename Json::const_iterator it2 = jobject.erase(jobject.find("b"), jobject.find("e")); + CHECK(jobject == Json({{"a", "a"}, {"e", true}})); + CHECK(*it2 == Json(true)); } } SECTION("different objects") { { - json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}}; - json jobject2 = {{"a", "a"}, {"b", 1}, {"c", 17u}}; + Json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}}; + Json jobject2 = {{"a", "a"}, {"b", 1}, {"c", 17u}}; CHECK_THROWS_WITH_AS(jobject.erase(jobject2.begin()), - "[json.exception.invalid_iterator.202] iterator does not fit current value", json::invalid_iterator&); + "[json.exception.invalid_iterator.202] iterator does not fit current value", typename Json::invalid_iterator&); CHECK_THROWS_WITH_AS(jobject.erase(jobject.begin(), jobject2.end()), - "[json.exception.invalid_iterator.203] iterators do not fit current value", json::invalid_iterator&); + "[json.exception.invalid_iterator.203] iterators do not fit current value", typename Json::invalid_iterator&); CHECK_THROWS_WITH_AS(jobject.erase(jobject2.begin(), jobject.end()), - "[json.exception.invalid_iterator.203] iterators do not fit current value", json::invalid_iterator&); + "[json.exception.invalid_iterator.203] iterators do not fit current value", typename Json::invalid_iterator&); CHECK_THROWS_WITH_AS(jobject.erase(jobject2.begin(), jobject2.end()), - "[json.exception.invalid_iterator.203] iterators do not fit current value", json::invalid_iterator&); + "[json.exception.invalid_iterator.203] iterators do not fit current value", typename Json::invalid_iterator&); } { - json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}}; - json jobject2 = {{"a", "a"}, {"b", 1}, {"c", 17u}}; + Json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}}; + Json jobject2 = {{"a", "a"}, {"b", 1}, {"c", 17u}}; CHECK_THROWS_WITH_AS(jobject.erase(jobject2.cbegin()), - "[json.exception.invalid_iterator.202] iterator does not fit current value", json::invalid_iterator&); + "[json.exception.invalid_iterator.202] iterator does not fit current value", typename Json::invalid_iterator&); CHECK_THROWS_WITH_AS(jobject.erase(jobject.cbegin(), jobject2.cend()), - "[json.exception.invalid_iterator.203] iterators do not fit current value", json::invalid_iterator&); + "[json.exception.invalid_iterator.203] iterators do not fit current value", typename Json::invalid_iterator&); CHECK_THROWS_WITH_AS(jobject.erase(jobject2.cbegin(), jobject.cend()), - "[json.exception.invalid_iterator.203] iterators do not fit current value", json::invalid_iterator&); + "[json.exception.invalid_iterator.203] iterators do not fit current value", typename Json::invalid_iterator&); CHECK_THROWS_WITH_AS(jobject.erase(jobject2.cbegin(), jobject2.cend()), - "[json.exception.invalid_iterator.203] iterators do not fit current value", json::invalid_iterator&); + "[json.exception.invalid_iterator.203] iterators do not fit current value", typename Json::invalid_iterator&); } } } @@ -947,61 +958,61 @@ TEST_CASE("element access 2") { SECTION("null") { - json j_nonobject(json::value_t::null); - CHECK_THROWS_WITH_AS(j_nonobject.erase("foo"), "[json.exception.type_error.307] cannot use erase() with null", json::type_error&); + Json j_nonobject(Json::value_t::null); + CHECK_THROWS_WITH_AS(j_nonobject.erase("foo"), "[json.exception.type_error.307] cannot use erase() with null", typename Json::type_error&); #ifdef JSON_HAS_CPP_17 - CHECK_THROWS_WITH_AS(j_nonobject.erase(std::string_view("foo")), "[json.exception.type_error.307] cannot use erase() with null", json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject.erase(std::string_view("foo")), "[json.exception.type_error.307] cannot use erase() with null", typename Json::type_error&); #endif } SECTION("boolean") { - json j_nonobject(json::value_t::boolean); - CHECK_THROWS_WITH_AS(j_nonobject.erase("foo"), "[json.exception.type_error.307] cannot use erase() with boolean", json::type_error&); + Json j_nonobject(Json::value_t::boolean); + CHECK_THROWS_WITH_AS(j_nonobject.erase("foo"), "[json.exception.type_error.307] cannot use erase() with boolean", typename Json::type_error&); #ifdef JSON_HAS_CPP_17 - CHECK_THROWS_WITH_AS(j_nonobject.erase(std::string_view("foo")), "[json.exception.type_error.307] cannot use erase() with boolean", json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject.erase(std::string_view("foo")), "[json.exception.type_error.307] cannot use erase() with boolean", typename Json::type_error&); #endif } SECTION("string") { - json j_nonobject(json::value_t::string); - CHECK_THROWS_WITH_AS(j_nonobject.erase("foo"), "[json.exception.type_error.307] cannot use erase() with string", json::type_error&); + Json j_nonobject(Json::value_t::string); + CHECK_THROWS_WITH_AS(j_nonobject.erase("foo"), "[json.exception.type_error.307] cannot use erase() with string", typename Json::type_error&); #ifdef JSON_HAS_CPP_17 - CHECK_THROWS_WITH_AS(j_nonobject.erase(std::string_view("foo")), "[json.exception.type_error.307] cannot use erase() with string", json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject.erase(std::string_view("foo")), "[json.exception.type_error.307] cannot use erase() with string", typename Json::type_error&); #endif } SECTION("array") { - json j_nonobject(json::value_t::array); - CHECK_THROWS_WITH_AS(j_nonobject.erase("foo"), "[json.exception.type_error.307] cannot use erase() with array", json::type_error&); + Json j_nonobject(Json::value_t::array); + CHECK_THROWS_WITH_AS(j_nonobject.erase("foo"), "[json.exception.type_error.307] cannot use erase() with array", typename Json::type_error&); #ifdef JSON_HAS_CPP_17 - CHECK_THROWS_WITH_AS(j_nonobject.erase(std::string_view("foo")), "[json.exception.type_error.307] cannot use erase() with array", json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject.erase(std::string_view("foo")), "[json.exception.type_error.307] cannot use erase() with array", typename Json::type_error&); #endif } SECTION("number (integer)") { - json j_nonobject(json::value_t::number_integer); - CHECK_THROWS_WITH_AS(j_nonobject.erase("foo"), "[json.exception.type_error.307] cannot use erase() with number", json::type_error&); + Json j_nonobject(Json::value_t::number_integer); + CHECK_THROWS_WITH_AS(j_nonobject.erase("foo"), "[json.exception.type_error.307] cannot use erase() with number", typename Json::type_error&); #ifdef JSON_HAS_CPP_17 - CHECK_THROWS_WITH_AS(j_nonobject.erase(std::string_view("foo")), "[json.exception.type_error.307] cannot use erase() with number", json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject.erase(std::string_view("foo")), "[json.exception.type_error.307] cannot use erase() with number", typename Json::type_error&); #endif } SECTION("number (floating-point)") { - json j_nonobject(json::value_t::number_float); - CHECK_THROWS_WITH_AS(j_nonobject.erase("foo"), "[json.exception.type_error.307] cannot use erase() with number", json::type_error&); + Json j_nonobject(Json::value_t::number_float); + CHECK_THROWS_WITH_AS(j_nonobject.erase("foo"), "[json.exception.type_error.307] cannot use erase() with number", typename Json::type_error&); #ifdef JSON_HAS_CPP_17 - CHECK_THROWS_WITH_AS(j_nonobject.erase(std::string_view("foo")), "[json.exception.type_error.307] cannot use erase() with number", json::type_error&); + CHECK_THROWS_WITH_AS(j_nonobject.erase(std::string_view("foo")), "[json.exception.type_error.307] cannot use erase() with number", typename Json::type_error&); #endif } } @@ -1048,8 +1059,8 @@ TEST_CASE("element access 2") { SECTION("null") { - json j_nonarray(json::value_t::null); - const json j_nonarray_const(j_nonarray); + Json j_nonarray(Json::value_t::null); + const Json j_nonarray_const(j_nonarray); CHECK(j_nonarray.find("foo") == j_nonarray.end()); CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end()); @@ -1062,8 +1073,8 @@ TEST_CASE("element access 2") SECTION("string") { - json j_nonarray(json::value_t::string); - const json j_nonarray_const(j_nonarray); + Json j_nonarray(Json::value_t::string); + const Json j_nonarray_const(j_nonarray); CHECK(j_nonarray.find("foo") == j_nonarray.end()); CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end()); @@ -1076,8 +1087,8 @@ TEST_CASE("element access 2") SECTION("object") { - json j_nonarray(json::value_t::object); - const json j_nonarray_const(j_nonarray); + Json j_nonarray(Json::value_t::object); + const Json j_nonarray_const(j_nonarray); CHECK(j_nonarray.find("foo") == j_nonarray.end()); CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end()); @@ -1090,8 +1101,8 @@ TEST_CASE("element access 2") SECTION("array") { - json j_nonarray(json::value_t::array); - const json j_nonarray_const(j_nonarray); + Json j_nonarray(Json::value_t::array); + const Json j_nonarray_const(j_nonarray); CHECK(j_nonarray.find("foo") == j_nonarray.end()); CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end()); @@ -1104,8 +1115,8 @@ TEST_CASE("element access 2") SECTION("boolean") { - json j_nonarray(json::value_t::boolean); - const json j_nonarray_const(j_nonarray); + Json j_nonarray(Json::value_t::boolean); + const Json j_nonarray_const(j_nonarray); CHECK(j_nonarray.find("foo") == j_nonarray.end()); CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end()); @@ -1118,8 +1129,8 @@ TEST_CASE("element access 2") SECTION("number (integer)") { - json j_nonarray(json::value_t::number_integer); - const json j_nonarray_const(j_nonarray); + Json j_nonarray(Json::value_t::number_integer); + const Json j_nonarray_const(j_nonarray); CHECK(j_nonarray.find("foo") == j_nonarray.end()); CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end()); @@ -1132,8 +1143,8 @@ TEST_CASE("element access 2") SECTION("number (unsigned)") { - json j_nonarray(json::value_t::number_unsigned); - const json j_nonarray_const(j_nonarray); + Json j_nonarray(Json::value_t::number_unsigned); + const Json j_nonarray_const(j_nonarray); CHECK(j_nonarray.find("foo") == j_nonarray.end()); CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end()); @@ -1146,8 +1157,8 @@ TEST_CASE("element access 2") SECTION("number (floating-point)") { - json j_nonarray(json::value_t::number_float); - const json j_nonarray_const(j_nonarray); + Json j_nonarray(Json::value_t::number_float); + const Json j_nonarray_const(j_nonarray); CHECK(j_nonarray.find("foo") == j_nonarray.end()); CHECK(j_nonarray_const.find("foo") == j_nonarray_const.end()); @@ -1197,8 +1208,8 @@ TEST_CASE("element access 2") { SECTION("null") { - json j_nonobject(json::value_t::null); - const json j_nonobject_const(json::value_t::null); + Json j_nonobject(Json::value_t::null); + const Json j_nonobject_const(Json::value_t::null); CHECK(j_nonobject.count("foo") == 0); CHECK(j_nonobject_const.count("foo") == 0); @@ -1211,8 +1222,8 @@ TEST_CASE("element access 2") SECTION("string") { - json j_nonobject(json::value_t::string); - const json j_nonobject_const(json::value_t::string); + Json j_nonobject(Json::value_t::string); + const Json j_nonobject_const(Json::value_t::string); CHECK(j_nonobject.count("foo") == 0); CHECK(j_nonobject_const.count("foo") == 0); @@ -1225,8 +1236,8 @@ TEST_CASE("element access 2") SECTION("object") { - json j_nonobject(json::value_t::object); - const json j_nonobject_const(json::value_t::object); + Json j_nonobject(Json::value_t::object); + const Json j_nonobject_const(Json::value_t::object); CHECK(j_nonobject.count("foo") == 0); CHECK(j_nonobject_const.count("foo") == 0); @@ -1239,8 +1250,8 @@ TEST_CASE("element access 2") SECTION("array") { - json j_nonobject(json::value_t::array); - const json j_nonobject_const(json::value_t::array); + Json j_nonobject(Json::value_t::array); + const Json j_nonobject_const(Json::value_t::array); CHECK(j_nonobject.count("foo") == 0); CHECK(j_nonobject_const.count("foo") == 0); @@ -1253,8 +1264,8 @@ TEST_CASE("element access 2") SECTION("boolean") { - json j_nonobject(json::value_t::boolean); - const json j_nonobject_const(json::value_t::boolean); + Json j_nonobject(Json::value_t::boolean); + const Json j_nonobject_const(Json::value_t::boolean); CHECK(j_nonobject.count("foo") == 0); CHECK(j_nonobject_const.count("foo") == 0); @@ -1267,8 +1278,8 @@ TEST_CASE("element access 2") SECTION("number (integer)") { - json j_nonobject(json::value_t::number_integer); - const json j_nonobject_const(json::value_t::number_integer); + Json j_nonobject(Json::value_t::number_integer); + const Json j_nonobject_const(Json::value_t::number_integer); CHECK(j_nonobject.count("foo") == 0); CHECK(j_nonobject_const.count("foo") == 0); @@ -1281,8 +1292,8 @@ TEST_CASE("element access 2") SECTION("number (unsigned)") { - json j_nonobject(json::value_t::number_unsigned); - const json j_nonobject_const(json::value_t::number_unsigned); + Json j_nonobject(Json::value_t::number_unsigned); + const Json j_nonobject_const(Json::value_t::number_unsigned); CHECK(j_nonobject.count("foo") == 0); CHECK(j_nonobject_const.count("foo") == 0); @@ -1295,8 +1306,8 @@ TEST_CASE("element access 2") SECTION("number (floating-point)") { - json j_nonobject(json::value_t::number_float); - const json j_nonobject_const(json::value_t::number_float); + Json j_nonobject(Json::value_t::number_float); + const Json j_nonobject_const(Json::value_t::number_float); CHECK(j_nonobject.count("foo") == 0); CHECK(j_nonobject_const.count("foo") == 0); @@ -1347,8 +1358,8 @@ TEST_CASE("element access 2") { SECTION("null") { - json j_nonobject(json::value_t::null); - const json j_nonobject_const(json::value_t::null); + Json j_nonobject(Json::value_t::null); + const Json j_nonobject_const(Json::value_t::null); CHECK(j_nonobject.contains("foo") == false); CHECK(j_nonobject_const.contains("foo") == false); @@ -1361,8 +1372,8 @@ TEST_CASE("element access 2") SECTION("string") { - json j_nonobject(json::value_t::string); - const json j_nonobject_const(json::value_t::string); + Json j_nonobject(Json::value_t::string); + const Json j_nonobject_const(Json::value_t::string); CHECK(j_nonobject.contains("foo") == false); CHECK(j_nonobject_const.contains("foo") == false); @@ -1375,8 +1386,8 @@ TEST_CASE("element access 2") SECTION("object") { - json j_nonobject(json::value_t::object); - const json j_nonobject_const(json::value_t::object); + Json j_nonobject(Json::value_t::object); + const Json j_nonobject_const(Json::value_t::object); CHECK(j_nonobject.contains("foo") == false); CHECK(j_nonobject_const.contains("foo") == false); @@ -1389,8 +1400,8 @@ TEST_CASE("element access 2") SECTION("array") { - json j_nonobject(json::value_t::array); - const json j_nonobject_const(json::value_t::array); + Json j_nonobject(Json::value_t::array); + const Json j_nonobject_const(Json::value_t::array); CHECK(j_nonobject.contains("foo") == false); CHECK(j_nonobject_const.contains("foo") == false); @@ -1403,8 +1414,8 @@ TEST_CASE("element access 2") SECTION("boolean") { - json j_nonobject(json::value_t::boolean); - const json j_nonobject_const(json::value_t::boolean); + Json j_nonobject(Json::value_t::boolean); + const Json j_nonobject_const(Json::value_t::boolean); CHECK(j_nonobject.contains("foo") == false); CHECK(j_nonobject_const.contains("foo") == false); @@ -1417,8 +1428,8 @@ TEST_CASE("element access 2") SECTION("number (integer)") { - json j_nonobject(json::value_t::number_integer); - const json j_nonobject_const(json::value_t::number_integer); + Json j_nonobject(Json::value_t::number_integer); + const Json j_nonobject_const(Json::value_t::number_integer); CHECK(j_nonobject.contains("foo") == false); CHECK(j_nonobject_const.contains("foo") == false); @@ -1431,8 +1442,8 @@ TEST_CASE("element access 2") SECTION("number (unsigned)") { - json j_nonobject(json::value_t::number_unsigned); - const json j_nonobject_const(json::value_t::number_unsigned); + Json j_nonobject(Json::value_t::number_unsigned); + const Json j_nonobject_const(Json::value_t::number_unsigned); CHECK(j_nonobject.contains("foo") == false); CHECK(j_nonobject_const.contains("foo") == false); @@ -1445,8 +1456,8 @@ TEST_CASE("element access 2") SECTION("number (floating-point)") { - json j_nonobject(json::value_t::number_float); - const json j_nonobject_const(json::value_t::number_float); + Json j_nonobject(Json::value_t::number_float); + const Json j_nonobject_const(Json::value_t::number_float); CHECK(j_nonobject.contains("foo") == false); CHECK(j_nonobject_const.contains("foo") == false); #ifdef JSON_HAS_CPP_17 @@ -1460,12 +1471,12 @@ TEST_CASE("element access 2") } #if !defined(JSON_NOEXCEPTION) -TEST_CASE("element access 2 (throwing tests)") +TEST_CASE_TEMPLATE("element access 2 (throwing tests)", Json, nlohmann::json, nlohmann::ordered_json) { SECTION("object") { - json j = {{"integer", 1}, {"unsigned", 1u}, {"floating", 42.23}, {"null", nullptr}, {"string", "hello world"}, {"boolean", true}, {"object", json::object()}, {"array", {1, 2, 3}}}; - const json j_const = {{"integer", 1}, {"unsigned", 1u}, {"floating", 42.23}, {"null", nullptr}, {"string", "hello world"}, {"boolean", true}, {"object", json::object()}, {"array", {1, 2, 3}}}; + Json j = {{"integer", 1}, {"unsigned", 1u}, {"floating", 42.23}, {"null", nullptr}, {"string", "hello world"}, {"boolean", true}, {"object", Json::object()}, {"array", {1, 2, 3}}}; + const Json j_const = {{"integer", 1}, {"unsigned", 1u}, {"floating", 42.23}, {"null", nullptr}, {"string", "hello world"}, {"boolean", true}, {"object", Json::object()}, {"array", {1, 2, 3}}}; SECTION("access specified element with default value") { @@ -1478,16 +1489,16 @@ TEST_CASE("element access 2 (throwing tests)") CHECK(j.value("/not/existing"_json_pointer, false) == false); CHECK(j.value("/not/existing"_json_pointer, "bar") == "bar"); CHECK(j.value("/not/existing"_json_pointer, 12.34) == Approx(12.34)); - CHECK(j.value("/not/existing"_json_pointer, json({{"foo", "bar"}})) == json({{"foo", "bar"}})); - CHECK(j.value("/not/existing"_json_pointer, json({10, 100})) == json({10, 100})); + CHECK(j.value("/not/existing"_json_pointer, Json({{"foo", "bar"}})) == Json({{"foo", "bar"}})); + CHECK(j.value("/not/existing"_json_pointer, Json({10, 100})) == Json({10, 100})); CHECK(j_const.value("/not/existing"_json_pointer, 2) == 2); CHECK(j_const.value("/not/existing"_json_pointer, 2u) == 2u); CHECK(j_const.value("/not/existing"_json_pointer, false) == false); CHECK(j_const.value("/not/existing"_json_pointer, "bar") == "bar"); CHECK(j_const.value("/not/existing"_json_pointer, 12.34) == Approx(12.34)); - CHECK(j_const.value("/not/existing"_json_pointer, json({{"foo", "bar"}})) == json({{"foo", "bar"}})); - CHECK(j_const.value("/not/existing"_json_pointer, json({10, 100})) == json({10, 100})); + CHECK(j_const.value("/not/existing"_json_pointer, Json({{"foo", "bar"}})) == Json({{"foo", "bar"}})); + CHECK(j_const.value("/not/existing"_json_pointer, Json({10, 100})) == Json({10, 100})); } } } From d4daaa897f48bf7bb2f96b46b84e49f32dd11daf Mon Sep 17 00:00:00 2001 From: Romain Reignier Date: Fri, 8 Jul 2022 08:12:00 +0200 Subject: [PATCH 4/8] Optimize output vector adapter write (#3569) * Add benchmark for cbor serialization and cbor binary data serialization * Use std::vector::insert method instead of std::copy in output_vector_adapter::write_characters This change increases a lot the performance when writing lots of binary data. --- .../detail/output/output_adapters.hpp | 2 +- single_include/nlohmann/json.hpp | 2 +- tests/benchmarks/src/benchmarks.cpp | 61 +++++++++++++++++++ 3 files changed, 63 insertions(+), 2 deletions(-) diff --git a/include/nlohmann/detail/output/output_adapters.hpp b/include/nlohmann/detail/output/output_adapters.hpp index 1cad57b19..f2a230320 100644 --- a/include/nlohmann/detail/output/output_adapters.hpp +++ b/include/nlohmann/detail/output/output_adapters.hpp @@ -53,7 +53,7 @@ class output_vector_adapter : public output_adapter_protocol JSON_HEDLEY_NON_NULL(2) void write_characters(const CharType* s, std::size_t length) override { - std::copy(s, s + length, std::back_inserter(v)); + v.insert(v.end(), s, s + length); } private: diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 65670d92c..cffbd7dce 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -14250,7 +14250,7 @@ class output_vector_adapter : public output_adapter_protocol JSON_HEDLEY_NON_NULL(2) void write_characters(const CharType* s, std::size_t length) override { - std::copy(s, s + length, std::back_inserter(v)); + v.insert(v.end(), s, s + length); } private: diff --git a/tests/benchmarks/src/benchmarks.cpp b/tests/benchmarks/src/benchmarks.cpp index 4f32a61a2..aa57e4347 100644 --- a/tests/benchmarks/src/benchmarks.cpp +++ b/tests/benchmarks/src/benchmarks.cpp @@ -1,6 +1,8 @@ #include "benchmark/benchmark.h" #include #include +#include +#include #include using json = nlohmann::json; @@ -107,4 +109,63 @@ BENCHMARK_CAPTURE(Dump, small_signed_ints / -, TEST_DATA_DIRECTORY "/regression/ BENCHMARK_CAPTURE(Dump, small_signed_ints / 4, TEST_DATA_DIRECTORY "/regression/small_signed_ints.json", 4); +////////////////////////////////////////////////////////////////////////////// +// serialize CBOR +////////////////////////////////////////////////////////////////////////////// +static void ToCbor(benchmark::State& state, const char* filename) +{ + std::ifstream f(filename); + std::string str((std::istreambuf_iterator(f)), std::istreambuf_iterator()); + json j = json::parse(str); + + while (state.KeepRunning()) + { + json::to_cbor(j); + } + + state.SetBytesProcessed(state.iterations() * json::to_cbor(j).size()); +} +BENCHMARK_CAPTURE(ToCbor, jeopardy, TEST_DATA_DIRECTORY "/jeopardy/jeopardy.json"); +BENCHMARK_CAPTURE(ToCbor, canada, TEST_DATA_DIRECTORY "/nativejson-benchmark/canada.json"); +BENCHMARK_CAPTURE(ToCbor, citm_catalog, TEST_DATA_DIRECTORY "/nativejson-benchmark/citm_catalog.json"); +BENCHMARK_CAPTURE(ToCbor, twitter, TEST_DATA_DIRECTORY "/nativejson-benchmark/twitter.json"); +BENCHMARK_CAPTURE(ToCbor, floats, TEST_DATA_DIRECTORY "/regression/floats.json"); +BENCHMARK_CAPTURE(ToCbor, signed_ints, TEST_DATA_DIRECTORY "/regression/signed_ints.json"); +BENCHMARK_CAPTURE(ToCbor, unsigned_ints, TEST_DATA_DIRECTORY "/regression/unsigned_ints.json"); +BENCHMARK_CAPTURE(ToCbor, small_signed_ints, TEST_DATA_DIRECTORY "/regression/small_signed_ints.json"); + +////////////////////////////////////////////////////////////////////////////// +// serialize binary CBOR +////////////////////////////////////////////////////////////////////////////// +static void BinaryToCbor(benchmark::State& state) +{ + std::vector data(256); + std::iota(data.begin(), data.end(), 0); + + auto it = data.begin(); + std::vector in; + in.reserve(state.range(0)); + for (int i = 0; i < state.range(0); ++i) + { + if (it == data.end()) + { + it = data.begin(); + } + + in.push_back(*it); + ++it; + } + + json::binary_t bin{in}; + json j{{"type", "binary"}, {"data", bin}}; + + while (state.KeepRunning()) + { + json::to_cbor(j); + } + + state.SetBytesProcessed(state.iterations() * json::to_cbor(j).size()); +} +BENCHMARK(BinaryToCbor)->RangeMultiplier(2)->Range(8, 8 << 12); + BENCHMARK_MAIN(); From 71bdaf57489dd879952d900624c508bb2a9960f1 Mon Sep 17 00:00:00 2001 From: Florian Albrechtskirchinger Date: Sun, 17 Jul 2022 13:43:32 +0200 Subject: [PATCH 5/8] Enable overriding test properties and set Unicode test timeouts (#3580) * CMake: Add TEST_PROPERTIES to json_test_set_test_options() Allow overriding test properties via json_test_set_test_options(). * CMake: Set timeouts for Unicode tests --- cmake/test.cmake | 37 ++++++++++++++++++++++++++++++++++--- tests/CMakeLists.txt | 7 ++++++- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/cmake/test.cmake b/cmake/test.cmake index b8b1250fb..bb840c6c0 100644 --- a/cmake/test.cmake +++ b/cmake/test.cmake @@ -50,9 +50,10 @@ endforeach() # [COMPILE_FEATURES ...] # [COMPILE_OPTIONS ...] # [LINK_LIBRARIES ...] -# [LINK_OPTIONS ...]) +# [LINK_OPTIONS ...] +# [TEST_PROPERTIES ...]) # -# Supply test- and standard-specific build settings. +# Supply test- and standard-specific build settings and/or test properties. # Specify multiple tests using a list e.g., "test-foo;test-bar". # # Must be called BEFORE the test is created. @@ -60,7 +61,7 @@ endforeach() function(json_test_set_test_options tests) cmake_parse_arguments(args "" "" - "CXX_STANDARDS;COMPILE_DEFINITIONS;COMPILE_FEATURES;COMPILE_OPTIONS;LINK_LIBRARIES;LINK_OPTIONS" + "CXX_STANDARDS;COMPILE_DEFINITIONS;COMPILE_FEATURES;COMPILE_OPTIONS;LINK_LIBRARIES;LINK_OPTIONS;TEST_PROPERTIES" ${ARGN}) if(NOT args_CXX_STANDARDS) @@ -91,10 +92,23 @@ function(json_test_set_test_options tests) target_compile_options(${test_interface} INTERFACE ${args_COMPILE_OPTIONS}) target_link_libraries (${test_interface} INTERFACE ${args_LINK_LIBRARIES}) target_link_options(${test_interface} INTERFACE ${args_LINK_OPTIONS}) + #set_target_properties(${test_interface} PROPERTIES JSON_TEST_PROPERTIES "${args_TEST_PROPERTIES}") + set_property(DIRECTORY PROPERTY + ${test_interface}_TEST_PROPERTIES "${args_TEST_PROPERTIES}" + ) endforeach() endforeach() endfunction() +# for internal use by _json_test_add_test() +function(_json_test_apply_test_properties test_target properties_target) + #get_target_property(test_properties ${properties_target} JSON_TEST_PROPERTIES) + get_property(test_properties DIRECTORY PROPERTY ${properties_target}_TEST_PROPERTIES) + if(test_properties) + set_tests_properties(${test_target} PROPERTIES ${test_properties}) + endif() +endfunction() + # for internal use by json_test_add_test_for() function(_json_test_add_test test_name file main cxx_standard) set(test_target ${test_name}_cpp${cxx_standard}) @@ -142,6 +156,23 @@ function(_json_test_add_test test_name file main cxx_standard) endif() set_tests_properties(${test_target} PROPERTIES LABELS "all" FIXTURES_REQUIRED TEST_DATA) + # apply standard-specific test properties + if(TARGET _json_test_interface__cpp_${cxx_standard}) + _json_test_apply_test_properties(${test_target} _json_test_interface__cpp_${cxx_standard}) + endif() + + # apply test-specific test properties + if(TARGET _json_test_interface_${test_name}) + _json_test_apply_test_properties(${test_target} _json_test_interface_${test_name}) + endif() + + # apply test- and standard-specific test properties + if(TARGET _json_test_interface_${test_name}_cpp_${cxx_standard}) + _json_test_apply_test_properties(${test_target} + _json_test_interface_${test_name}_cpp_${cxx_standard} + ) + endif() + if(JSON_Valgrind) add_test(NAME ${test_target}_valgrind COMMAND ${memcheck_command} $ ${DOCTEST_TEST_FILTER} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 8f9240f1a..a664f4baf 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -80,12 +80,17 @@ endif() # disable exceptions for test-disabled_exceptions json_test_set_test_options(test-disabled_exceptions COMPILE_DEFINITIONS JSON_NOEXCEPTION) if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU") -json_test_set_test_options(test-disabled_exceptions COMPILE_OPTIONS -fno-exceptions) + json_test_set_test_options(test-disabled_exceptions COMPILE_OPTIONS -fno-exceptions) elseif (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") # disabled due to https://github.com/nlohmann/json/discussions/2824 #json_test_set_test_options(test-disabled_exceptions COMPILE_DEFINITIONS _HAS_EXCEPTIONS=0 COMPILE_OPTIONS /EH) endif() +# set timeouts for Unicode tests +json_test_set_test_options("test-unicode2;test-unicode3;test-unicode4;test-unicode5" + TEST_PROPERTIES "TIMEOUT_AFTER_MATCH;1500$UTF-8 strings checked" +) + ############################################################################# # add unit tests ############################################################################# From d64d40518ce49d13a8f16112ad31d5f8933a11f1 Mon Sep 17 00:00:00 2001 From: NN <580536+NN---@users.noreply.github.com> Date: Sun, 17 Jul 2022 14:43:55 +0300 Subject: [PATCH 6/8] Ignore output directory (#3572) * Ignore output directory * Update .gitignore Co-authored-by: Niels Lohmann Co-authored-by: Niels Lohmann --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 72eb2c225..2c29d2c52 100644 --- a/.gitignore +++ b/.gitignore @@ -9,9 +9,10 @@ /.idea /cmake-build-* - +# Visual Studio Code /.vs/ /.vscode/ +/out/ # clangd cache /.cache/ From a15683e348687a212ea9f4c22284f3c855cdad46 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Mon, 18 Jul 2022 17:48:42 +0200 Subject: [PATCH 7/8] :memo: add badge for https://repology.org/project/nlohmann-json/versions (#3586) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 220b3a9f1..c94c3eea2 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ [![Documentation](https://img.shields.io/badge/docs-mkdocs-blue.svg)](https://json.nlohmann.me) [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/nlohmann/json/master/LICENSE.MIT) [![GitHub Releases](https://img.shields.io/github/release/nlohmann/json.svg)](https://github.com/nlohmann/json/releases) +[![Packaging status](https://repology.org/badge/tiny-repos/nlohmann-json.svg)](https://repology.org/project/nlohmann-json/versions) [![GitHub Downloads](https://img.shields.io/github/downloads/nlohmann/json/total)](https://github.com/nlohmann/json/releases) [![GitHub Issues](https://img.shields.io/github/issues/nlohmann/json.svg)](https://github.com/nlohmann/json/issues) [![Average time to resolve an issue](https://isitmaintained.com/badge/resolution/nlohmann/json.svg)](https://isitmaintained.com/project/nlohmann/json "Average time to resolve an issue") From 2a9ae2b48783609263414bdb9c0ef094787c2817 Mon Sep 17 00:00:00 2001 From: Jake Zimmerman Date: Mon, 18 Jul 2022 08:55:44 -0700 Subject: [PATCH 8/8] Make certain usage patterns more prominent in the README (#3557) * Make certain usage patterns more prominent in the README We use this library extensively where I work. After pairing with many teammates, I've learned that one common stumbling point when using this library is how to first get a JSON value in the first place (because once they have a variable of type `json` in hand, the API is intuitive and mostly does what you expect). With that in mind, I've added two subsections to the top of the Examples section: how to read JSON from a file, and how to hardcode a JSON literal. I understand that these are already documented elsewhere in the Examples section, and so these new subsections are technically redundant. But to defend this choice: - Redundancy in docs is actually good, because not everyone consumes docs in the same way or in the same order. - Having these things called out explicitly in isolation encourages people to get something working faster. In later sections, these examples are presented alongside many other options. Having to choose between alternatives gets in the way of quickly prototyping something. If you have further suggestions for how to improve or modify these docs I'm open to them. The changes included here would really make a huge improvement in the productivity of newer members of my team using this library. * Remove old TOC entry * Put the section back * Another tweak --- README.md | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c94c3eea2..654aa27b4 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,8 @@ - [Sponsors](#sponsors) - [Support](#support) ([documentation](https://json.nlohmann.me), [FAQ](https://json.nlohmann.me/home/faq/), [discussions](https://github.com/nlohmann/json/discussions), [API](https://json.nlohmann.me/api/basic_json/), [bug issues](https://github.com/nlohmann/json/issues)) - [Examples](#examples) + - [Read JSON from a file](#read-json-from-a-file) + - [Creating `json` objects from JSON literals](#creating-json-objects-from-json-literals) - [JSON as first-class data type](#json-as-first-class-data-type) - [Serialization / Deserialization](#serialization--deserialization) - [STL-like access](#stl-like-access) @@ -98,7 +100,66 @@ There is also a [**docset**](https://github.com/Kapeli/Dash-User-Contributions/t ## Examples -Beside the examples below, you may want to check the [documentation](https://json.nlohmann.me/) where each function contains a separate code example (e.g., check out [`emplace()`](https://json.nlohmann.me/api/basic_json/emplace/)). All [example files](https://github.com/nlohmann/json/tree/develop/docs/examples) can be compiled and executed on their own (e.g., file [emplace.cpp](https://github.com/nlohmann/json/blob/develop/docs/examples/emplace.cpp)). +Here are some examples to give you an idea how to use the class. + +Beside the examples below, you may want to: + +→ Check the [documentation](https://json.nlohmann.me/)\ +→ Browse the [standalone example files](https://github.com/nlohmann/json/tree/develop/docs/examples) + +Every API function (documented in the [API Documentation](https://json.nlohmann.me/api/basic_json/)) has a corresponding standalone example file. For example, the [`emplace()`](https://json.nlohmann.me/api/basic_json/emplace/) function has a matching [emplace.cpp](https://github.com/nlohmann/json/blob/develop/docs/examples/emplace.cpp) example file. + +### Read JSON from a file + +The `json` class provides an API for manipulating a JSON value. To create a `json` object by reading a JSON file: + +```cpp +#include +#include +using json = nlohmann::json; + +// ... + +std::ifstream f("example.json"); +json data = json::parse(f); +``` + +### Creating `json` objects from JSON literals + +Assume you want to create hard-code this literal JSON value in a file, as a `json` object: + +```json +{ + "pi": 3.141, + "happy": true +} +``` + +There are various options: + +```cpp +// Using (raw) string literals and json::parse +json ex1 = json::parse(R"( + { + "pi": 3.141, + "happy": true + } +)"); + +// Using user-defined (raw) string literals +json ex2 = R"( + { + "pi": 3.141, + "happy": true + } +)"_json; + +// Using initializer lists +json ex3 = { + {"happy", true}, + {"pi", 3.141}, +}; +``` ### JSON as first-class data type