From 6e4910d5c5638bedbc3ff650d1b6b91249a927a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20DELRIEU?= Date: Sat, 17 Jun 2017 14:24:07 +0200 Subject: [PATCH 1/2] add pair/tuple conversions --- src/json.hpp | 69 ++++++++++++++++++++++++++++++++++ test/src/unit-constructor1.cpp | 52 +++++++++++++++++++++++++ 2 files changed, 121 insertions(+) diff --git a/src/json.hpp b/src/json.hpp index a4ea2c8fc..ccf83d5ee 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -465,6 +465,39 @@ using enable_if_t = typename std::enable_if::type; template using uncvref_t = typename std::remove_cv::type>::type; +// implementation of C++14 index_sequence and affiliates +// source: https://stackoverflow.com/a/32223343 +template +struct index_sequence +{ + using type = index_sequence; + using value_type = std::size_t; + static constexpr std::size_t size() noexcept + { + return sizeof...(Ints); + } +}; + +template +struct merge_and_renumber; + +template +struct merge_and_renumber, index_sequence> + : index_sequence < I1..., (sizeof...(I1) + I2)... > + { }; + +template +struct make_index_sequence + : merge_and_renumber < typename make_index_sequence < N / 2 >::type, + typename make_index_sequence < N - N / 2 >::type > +{ }; + +template<> struct make_index_sequence<0> : index_sequence<> { }; +template<> struct make_index_sequence<1> : index_sequence<0> { }; + +template +using index_sequence_for = make_index_sequence; + /* Implementation of two C++17 constructs: conjunction, negation. This is needed to avoid evaluating all the traits in a condition @@ -866,6 +899,24 @@ void to_json(BasicJsonType& j, T (&arr)[N]) external_constructor::construct(j, arr); } +template +void to_json(BasicJsonType& j, const std::pair& p) +{ + j = {p.first, p.second}; +} + +template +void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence) +{ + j = {std::get(t)...}; +} + +template +void to_json(BasicJsonType& j, const std::tuple& t) +{ + to_json_tuple_impl(j, t, index_sequence_for {}); +} + /////////////// // from_json // /////////////// @@ -1094,6 +1145,24 @@ void from_json(const BasicJsonType& j, ArithmeticType& val) } } +template +void from_json(const BasicJsonType& j, std::pair& p) +{ + p = {j.at(0), j.at(1)}; +} + +template +void from_json_tuple_impl(const BasicJsonType& j, Tuple& t, index_sequence) +{ + t = std::make_tuple(j.at(Idx)...); +} + +template +void from_json(const BasicJsonType& j, std::tuple& t) +{ + from_json_tuple_impl(j, t, index_sequence_for {}); +} + struct to_json_fn { private: diff --git a/test/src/unit-constructor1.cpp b/test/src/unit-constructor1.cpp index 0e56db7c5..a74e9a638 100644 --- a/test/src/unit-constructor1.cpp +++ b/test/src/unit-constructor1.cpp @@ -239,6 +239,58 @@ TEST_CASE("constructors") CHECK(j == j_reference); } + SECTION("std::pair") + { + std::pair p{1.0, "string"}; + json j(p); + + CHECK(j.type() == json::value_t::array); + REQUIRE(j.size() == 2); + CHECK(j[0] == std::get<0>(p)); + CHECK(j[1] == std::get<1>(p)); + } + + SECTION("std::pair with discarded values") + { + json j{1, 2.0, "string"}; + + const auto p = j.get>(); + CHECK(p.first == j[0]); + CHECK(p.second == j[1]); + } + + SECTION("std::tuple") + { + const auto t = std::make_tuple(1.0, "string", 42, std::vector {0, 1}); + json j(t); + + CHECK(j.type() == json::value_t::array); + REQUIRE(j.size() == 4); + CHECK(j[0] == std::get<0>(t)); + CHECK(j[1] == std::get<1>(t)); + CHECK(j[2] == std::get<2>(t)); + CHECK(j[3][0] == 0); + CHECK(j[3][1] == 1); + } + + SECTION("std::tuple with discarded values") + { + json j{1, 2.0, "string", 42}; + + const auto t = j.get>(); + CHECK(std::get<0>(t) == j[0]); + CHECK(std::get<1>(t) == j[1]); + CHECK(std::get<2>(t) == j[2]); + } + + SECTION("std::pair/tuple failures") + { + json j{1}; + + CHECK_THROWS((j.get>())); + CHECK_THROWS((j.get>())); + } + SECTION("std::forward_list") { std::forward_list a {json(1), json(1u), json(2.2), json(false), json("string"), json()}; From 08d781058c118836c9fc8a50b7d4675558ec08d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20DELRIEU?= Date: Mon, 19 Jun 2017 12:03:38 +0200 Subject: [PATCH 2/2] add from_json support for std::array --- src/json.hpp | 11 ++++++++++- test/src/unit-constructor1.cpp | 8 ++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index ccf83d5ee..87c8d21f8 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -1063,6 +1063,15 @@ auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, prio }); } +template +void from_json_array_impl(const BasicJsonType& j, std::array& arr, priority_tag<2>) +{ + for (std::size_t i = 0; i < N; ++i) + { + arr[i] = j.at(i).template get(); + } +} + template::value and std::is_convertible::value and @@ -1074,7 +1083,7 @@ void from_json(const BasicJsonType& j, CompatibleArrayType& arr) JSON_THROW(type_error::create(302, "type must be array, but is " + j.type_name())); } - from_json_array_impl(j, arr, priority_tag<1> {}); + from_json_array_impl(j, arr, priority_tag<2> {}); } template(t) == j[2]); } - SECTION("std::pair/tuple failures") + SECTION("std::pair/tuple/array failures") { json j{1}; CHECK_THROWS((j.get>())); CHECK_THROWS((j.get>())); + CHECK_THROWS((j.get>())); } SECTION("std::forward_list") @@ -299,12 +300,15 @@ TEST_CASE("constructors") CHECK(j == j_reference); } - SECTION("std::array") + SECTION("std::array") { std::array a {{json(1), json(1u), json(2.2), json(false), json("string"), json()}}; json j(a); CHECK(j.type() == json::value_t::array); CHECK(j == j_reference); + + const auto a2 = j.get>(); + CHECK(a2 == a); } SECTION("std::vector")