Skip to content

Commit

Permalink
Provide a from_json overload for std::map
Browse files Browse the repository at this point in the history
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
  • Loading branch information
theodelrieu committed May 28, 2018
1 parent 567fe9b commit c5e63fd
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 0 deletions.
20 changes: 20 additions & 0 deletions include/nlohmann/detail/conversions/from_json.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <ciso646> // and, not
#include <forward_list> // forward_list
#include <iterator> // inserter, front_inserter, end
#include <map> // map
#include <string> // string
#include <tuple> // tuple, make_tuple
#include <type_traits> // is_arithmetic, is_same, is_enum, underlying_type, is_convertible
Expand Down Expand Up @@ -277,6 +278,25 @@ void from_json(const BasicJsonType& j, std::tuple<Args...>& t)
from_json_tuple_impl(j, t, index_sequence_for<Args...> {});
}

template <typename BasicJsonType, typename Key, typename Value,
typename = enable_if_t<not std::is_constructible<
typename BasicJsonType::string_t, Key>::value>>
void from_json(const BasicJsonType& j, std::map<Key, Value>& 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<Key>(), p.at(1).template get<Value>());
}
}

struct from_json_fn
{
private:
Expand Down
20 changes: 20 additions & 0 deletions single_include/nlohmann/json.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -909,6 +909,7 @@ inline bool operator<(const value_t lhs, const value_t rhs) noexcept
#include <ciso646> // and, not
#include <forward_list> // forward_list
#include <iterator> // inserter, front_inserter, end
#include <map> // map
#include <string> // string
#include <tuple> // tuple, make_tuple
#include <type_traits> // is_arithmetic, is_same, is_enum, underlying_type, is_convertible
Expand Down Expand Up @@ -1185,6 +1186,25 @@ void from_json(const BasicJsonType& j, std::tuple<Args...>& t)
from_json_tuple_impl(j, t, index_sequence_for<Args...> {});
}

template <typename BasicJsonType, typename Key, typename Value,
typename = enable_if_t<not std::is_constructible<
typename BasicJsonType::string_t, Key>::value>>
void from_json(const BasicJsonType& j, std::map<Key, Value>& 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<Key>(), p.at(1).template get<Value>());
}
}

struct from_json_fn
{
private:
Expand Down
21 changes: 21 additions & 0 deletions test/src/unit-conversions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1079,6 +1079,26 @@ TEST_CASE("value conversion")
j5.get<std::unordered_set<std::string>>();
}

SECTION("std::map (array of pairs)")
{
std::map<int, int> m{{0, 1}, {1, 2}, {2, 3}};
json j6 = m;

auto m2 = j6.get<std::map<int, int>>();
CHECK(m == m2);

json j7 = {0, 1, 2, 3};
CHECK_THROWS_AS((j7.get<std::map<int, int>>()), json::type_error&);
CHECK_THROWS_WITH((j7.get<std::map<int, int>>()), "[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<std::map<int, int>>();
CHECK(m == m2);
}
}

SECTION("exception in case of a non-object type")
{
CHECK_THROWS_AS((json().get<std::list<int>>()), json::type_error&);
Expand All @@ -1094,6 +1114,7 @@ TEST_CASE("value conversion")
CHECK_THROWS_WITH((json().get<std::vector<json>>()), "[json.exception.type_error.302] type must be array, but is null");
CHECK_THROWS_WITH((json().get<std::list<json>>()), "[json.exception.type_error.302] type must be array, but is null");
CHECK_THROWS_WITH((json().get<std::valarray<int>>()), "[json.exception.type_error.302] type must be array, but is null");
CHECK_THROWS_WITH((json().get<std::map<int, int>>()), "[json.exception.type_error.302] type must be array, but is null");
}
}
}
Expand Down

0 comments on commit c5e63fd

Please sign in to comment.