From cea39dfaa892115adb05985221cfa2090f92bab9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20DELRIEU?= Date: Tue, 6 Jun 2017 14:18:32 +0200 Subject: [PATCH] fix #600 Instead of calling CompatibleObjectType iterator-range constructor, first convert json::value_type to CompatibleObjectType::value_type --- src/json.hpp | 28 +++++++++++++++----- test/src/unit-constructor1.cpp | 48 +++++++++++++++++++++++++--------- 2 files changed, 56 insertions(+), 20 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index 87e4e546..d5618fb8 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -867,11 +867,11 @@ void to_json(BasicJsonType& j, T (&arr)[N]) } template ::value, int> = 0> + enable_if_t::value, int> = 0> void to_json(BasicJsonType& j, std::pair const& p) { - j[p.first] = p.second; + j[p.first] = p.second; } /////////////// @@ -1046,10 +1046,24 @@ void from_json(const BasicJsonType& j, CompatibleObjectType& obj) auto inner_object = j.template get_ptr(); using std::begin; using std::end; + using value_type = typename CompatibleObjectType::value_type; + std::vector v; + v.reserve(j.size()); + std::transform( + inner_object->begin(), inner_object->end(), std::back_inserter(v), + [](typename BasicJsonType::object_t::value_type const & p) + { + return value_type + { + p.first, + p.second + .template get()}; + }); // we could avoid the assignment, but this might require a for loop, which // might be less efficient than the container constructor for some // containers (would it?) - obj = CompatibleObjectType(begin(*inner_object), end(*inner_object)); + obj = CompatibleObjectType(std::make_move_iterator(begin(v)), + std::make_move_iterator(end(v))); } // overload for arithmetic types, not chosen for basic_json template arguments @@ -1096,8 +1110,8 @@ void from_json(const BasicJsonType& j, ArithmeticType& val) } template ::value, int> = 0> + enable_if_t::value, int> = 0> void from_json(const BasicJsonType& j, std::pair& p) { if (not j.is_object()) @@ -1112,7 +1126,7 @@ void from_json(const BasicJsonType& j, std::pair& p) JSON_THROW(other_error::create(502, "conversion to std::pair requires the object to have exactly one field, but it has " + std::to_string(size))); } auto const& obj = *inner_object->begin(); - // cannot use *inner_object, need to convert both members + // cannot use *inner_object, need to convert both members p = std::make_pair(obj.first, obj.second.template get()); } diff --git a/test/src/unit-constructor1.cpp b/test/src/unit-constructor1.cpp index f16e15c1..db100a69 100644 --- a/test/src/unit-constructor1.cpp +++ b/test/src/unit-constructor1.cpp @@ -158,16 +158,27 @@ TEST_CASE("constructors") SECTION("std::pair") { - std::pair p{"first", "second"}; - json j(p); + std::pair p{"first", "second"}; + json j(p); - CHECK((j.get() == p)); + CHECK((j.get() == p)); - std::pair p2{"first", 1}; - // use char const* - json j2(std::make_pair("first", 1)); + std::pair p2{"first", 1}; + // use char const* + json j2(std::make_pair("first", 1)); - CHECK((j2.get() == p2)); + CHECK((j2.get() == p2)); + } + + SECTION("std::map #600") + { + std::map m; + m["a"] = "b"; + m["c"] = "d"; + m["e"] = "f"; + + json j(m); + CHECK((j.get() == m)); } SECTION("std::map") @@ -971,12 +982,23 @@ TEST_CASE("constructors") SECTION("std::pair with error") { - json j{{"too", "much"}, {"string", "fields"}}; - CHECK_THROWS_AS((j.get>()), json::other_error); - CHECK_THROWS_WITH((j.get>()), - "[json.exception.other_error.502] conversion " - "to std::pair requires the object to have " - "exactly one field, but it has 2"); + SECTION("wrong field number") + { + json j{{"too", "much"}, {"string", "fields"}}; + CHECK_THROWS_AS((j.get>()), json::other_error); + CHECK_THROWS_WITH((j.get>()), + "[json.exception.other_error.502] conversion " + "to std::pair requires the object to have " + "exactly one field, but it has 2"); + } + + SECTION("wrong JSON type") + { + json j(42); + CHECK_THROWS_AS((j.get>()), json::type_error); + CHECK_THROWS_WITH((j.get>()), + "[json.exception.type_error.302] type must be object, but is number"); + } }