diff --git a/src/json.hpp b/src/json.hpp index a1c15528e..146b52867 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 // /////////////// @@ -1012,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 @@ -1023,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 +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..9dbf45405 100644 --- a/test/src/unit-constructor1.cpp +++ b/test/src/unit-constructor1.cpp @@ -239,6 +239,59 @@ 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/array failures") + { + json j{1}; + + CHECK_THROWS((j.get>())); + 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()}; @@ -247,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")