From c5e63fd68430469f3734b0468b1db2e9d4fc5674 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20DELRIEU?= Date: Mon, 14 May 2018 11:51:37 +0200 Subject: [PATCH] Provide a from_json overload for std::map This overload is chosen only when BasicJsonType::string_t is not constructible from std::map::key_type. Currently, converting a map to json treats it as an array of pairs. fixes #1079 --- .../nlohmann/detail/conversions/from_json.hpp | 20 ++++++++++++++++++ single_include/nlohmann/json.hpp | 20 ++++++++++++++++++ test/src/unit-conversions.cpp | 21 +++++++++++++++++++ 3 files changed, 61 insertions(+) diff --git a/include/nlohmann/detail/conversions/from_json.hpp b/include/nlohmann/detail/conversions/from_json.hpp index eccc04f1..ac4cea5f 100644 --- a/include/nlohmann/detail/conversions/from_json.hpp +++ b/include/nlohmann/detail/conversions/from_json.hpp @@ -5,6 +5,7 @@ #include // and, not #include // forward_list #include // inserter, front_inserter, end +#include // map #include // string #include // tuple, make_tuple #include // is_arithmetic, is_same, is_enum, underlying_type, is_convertible @@ -277,6 +278,25 @@ void from_json(const BasicJsonType& j, std::tuple& t) from_json_tuple_impl(j, t, index_sequence_for {}); } +template ::value>> +void from_json(const BasicJsonType& j, std::map& m) +{ + if (JSON_UNLIKELY(not j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); + } + for (const auto& p : j) + { + if (JSON_UNLIKELY(not p.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(p.type_name()))); + } + m.emplace(p.at(0).template get(), p.at(1).template get()); + } +} + struct from_json_fn { private: diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 8c9942bb..e3112f77 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -909,6 +909,7 @@ inline bool operator<(const value_t lhs, const value_t rhs) noexcept #include // and, not #include // forward_list #include // inserter, front_inserter, end +#include // map #include // string #include // tuple, make_tuple #include // is_arithmetic, is_same, is_enum, underlying_type, is_convertible @@ -1185,6 +1186,25 @@ void from_json(const BasicJsonType& j, std::tuple& t) from_json_tuple_impl(j, t, index_sequence_for {}); } +template ::value>> +void from_json(const BasicJsonType& j, std::map& m) +{ + if (JSON_UNLIKELY(not j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); + } + for (const auto& p : j) + { + if (JSON_UNLIKELY(not p.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(p.type_name()))); + } + m.emplace(p.at(0).template get(), p.at(1).template get()); + } +} + struct from_json_fn { private: diff --git a/test/src/unit-conversions.cpp b/test/src/unit-conversions.cpp index 351dec8a..79ccf681 100644 --- a/test/src/unit-conversions.cpp +++ b/test/src/unit-conversions.cpp @@ -1079,6 +1079,26 @@ TEST_CASE("value conversion") j5.get>(); } + SECTION("std::map (array of pairs)") + { + std::map m{{0, 1}, {1, 2}, {2, 3}}; + json j6 = m; + + auto m2 = j6.get>(); + CHECK(m == m2); + + json j7 = {0, 1, 2, 3}; + CHECK_THROWS_AS((j7.get>()), json::type_error&); + CHECK_THROWS_WITH((j7.get>()), "[json.exception.type_error.302] type must be array, but is number"); + + SECTION("superfluous entries") + { + json j8 = {{0, 1, 2}, {1, 2, 3}, {2, 3, 4}}; + m2 = j8.get>(); + CHECK(m == m2); + } + } + SECTION("exception in case of a non-object type") { CHECK_THROWS_AS((json().get>()), json::type_error&); @@ -1094,6 +1114,7 @@ TEST_CASE("value conversion") CHECK_THROWS_WITH((json().get>()), "[json.exception.type_error.302] type must be array, but is null"); CHECK_THROWS_WITH((json().get>()), "[json.exception.type_error.302] type must be array, but is null"); CHECK_THROWS_WITH((json().get>()), "[json.exception.type_error.302] type must be array, but is null"); + CHECK_THROWS_WITH((json().get>()), "[json.exception.type_error.302] type must be array, but is null"); } } }