From 2b37d7ed86926f0c7c865651b4dee29aaae2015b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20DELRIEU?= <theo.delrieu@tanker.io> Date: Mon, 18 Jun 2018 10:53:30 +0200 Subject: [PATCH] from_json: add overload for std::unordered_map Fixes #1133 --- .../nlohmann/detail/conversions/from_json.hpp | 20 ++++++++ test/src/unit-conversions.cpp | 50 +++++++++++++++++-- 2 files changed, 66 insertions(+), 4 deletions(-) diff --git a/include/nlohmann/detail/conversions/from_json.hpp b/include/nlohmann/detail/conversions/from_json.hpp index e77ad5d2..7fe19f57 100644 --- a/include/nlohmann/detail/conversions/from_json.hpp +++ b/include/nlohmann/detail/conversions/from_json.hpp @@ -9,6 +9,7 @@ #include <string> // string #include <tuple> // tuple, make_tuple #include <type_traits> // is_arithmetic, is_same, is_enum, underlying_type, is_convertible +#include <unordered_map> // unordered_map #include <utility> // pair, declval #include <valarray> // valarray @@ -297,6 +298,25 @@ void from_json(const BasicJsonType& j, std::map<Key, Value, Compare, Allocator>& } } +template <typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator, + typename = enable_if_t<not std::is_constructible< + typename BasicJsonType::string_t, Key>::value>> +void from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyEqual, Allocator>& 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: diff --git a/test/src/unit-conversions.cpp b/test/src/unit-conversions.cpp index 79ccf681..0691bbf4 100644 --- a/test/src/unit-conversions.cpp +++ b/test/src/unit-conversions.cpp @@ -40,6 +40,14 @@ using nlohmann::json; #include <unordered_set> #include <valarray> +namespace +{ +template <typename MapType> +void map_type_conversion_checks() +{ +} +} + TEST_CASE("value conversion") { SECTION("get an object (explicit)") @@ -1088,14 +1096,48 @@ TEST_CASE("value conversion") CHECK(m == m2); json j7 = {0, 1, 2, 3}; + json j8 = 2; 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"); + CHECK_THROWS_AS((j8.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"); + CHECK_THROWS_WITH((j8.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); + json j9 = {{0, 1, 2}, {1, 2, 3}, {2, 3, 4}}; + m2 = j9.get<std::map<int, int>>(); + CHECK(m == m2); + } + } + + SECTION("std::unordered_map (array of pairs)") + { + std::unordered_map<int, int> m{{0, 1}, {1, 2}, {2, 3}}; + json j6 = m; + + auto m2 = j6.get<std::unordered_map<int, int>>(); + CHECK(m == m2); + + json j7 = {0, 1, 2, 3}; + json j8 = 2; + CHECK_THROWS_AS((j7.get<std::unordered_map<int, int>>()), json::type_error&); + CHECK_THROWS_AS((j8.get<std::unordered_map<int, int>>()), json::type_error&); + CHECK_THROWS_WITH((j7.get<std::unordered_map<int, int>>()), + "[json.exception.type_error.302] type must be array, " + "but is number"); + CHECK_THROWS_WITH((j8.get<std::unordered_map<int, int>>()), + "[json.exception.type_error.302] type must be array, " + "but is number"); + + SECTION("superfluous entries") + { + json j9{{0, 1, 2}, {1, 2, 3}, {2, 3, 4}}; + m2 = j9.get<std::unordered_map<int, int>>(); + CHECK(m == m2); } }