Merge pull request #624 from theodelrieu/feature/pair_tuple_conversions
add pair/tuple conversions
This commit is contained in:
		
						commit
						4e6f548c0b
					
				
					 2 changed files with 136 additions and 2 deletions
				
			
		
							
								
								
									
										80
									
								
								src/json.hpp
									
										
									
									
									
								
							
							
						
						
									
										80
									
								
								src/json.hpp
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -465,6 +465,39 @@ using enable_if_t = typename std::enable_if<B, T>::type;
 | 
			
		|||
template<typename T>
 | 
			
		||||
using uncvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
 | 
			
		||||
 | 
			
		||||
// implementation of C++14 index_sequence and affiliates
 | 
			
		||||
// source: https://stackoverflow.com/a/32223343
 | 
			
		||||
template <std::size_t... Ints>
 | 
			
		||||
struct index_sequence
 | 
			
		||||
{
 | 
			
		||||
    using type = index_sequence;
 | 
			
		||||
    using value_type = std::size_t;
 | 
			
		||||
    static constexpr std::size_t size() noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return sizeof...(Ints);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <class Sequence1, class Sequence2>
 | 
			
		||||
struct merge_and_renumber;
 | 
			
		||||
 | 
			
		||||
template <std::size_t... I1, std::size_t... I2>
 | 
			
		||||
struct merge_and_renumber<index_sequence<I1...>, index_sequence<I2...>>
 | 
			
		||||
        : index_sequence < I1..., (sizeof...(I1) + I2)... >
 | 
			
		||||
          { };
 | 
			
		||||
 | 
			
		||||
template <std::size_t N>
 | 
			
		||||
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<typename... Ts>
 | 
			
		||||
using index_sequence_for = make_index_sequence<sizeof...(Ts)>;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
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<value_t::array>::construct(j, arr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BasicJsonType, typename... Args>
 | 
			
		||||
void to_json(BasicJsonType& j, const std::pair<Args...>& p)
 | 
			
		||||
{
 | 
			
		||||
    j = {p.first, p.second};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BasicJsonType, typename Tuple, std::size_t... Idx>
 | 
			
		||||
void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence<Idx...>)
 | 
			
		||||
{
 | 
			
		||||
    j = {std::get<Idx>(t)...};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BasicJsonType, typename... Args>
 | 
			
		||||
void to_json(BasicJsonType& j, const std::tuple<Args...>& t)
 | 
			
		||||
{
 | 
			
		||||
    to_json_tuple_impl(j, t, index_sequence_for<Args...> {});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
///////////////
 | 
			
		||||
// from_json //
 | 
			
		||||
///////////////
 | 
			
		||||
| 
						 | 
				
			
			@ -1012,6 +1063,15 @@ auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, prio
 | 
			
		|||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BasicJsonType, typename T, std::size_t N>
 | 
			
		||||
void from_json_array_impl(const BasicJsonType& j, std::array<T, N>& arr, priority_tag<2>)
 | 
			
		||||
{
 | 
			
		||||
    for (std::size_t i = 0; i < N; ++i)
 | 
			
		||||
    {
 | 
			
		||||
        arr[i] = j.at(i).template get<T>();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename BasicJsonType, typename CompatibleArrayType,
 | 
			
		||||
         enable_if_t<is_compatible_array_type<BasicJsonType, CompatibleArrayType>::value and
 | 
			
		||||
                     std::is_convertible<BasicJsonType, typename CompatibleArrayType::value_type>::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<typename BasicJsonType, typename CompatibleObjectType,
 | 
			
		||||
| 
						 | 
				
			
			@ -1094,6 +1154,24 @@ void from_json(const BasicJsonType& j, ArithmeticType& val)
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BasicJsonType, typename... Args>
 | 
			
		||||
void from_json(const BasicJsonType& j, std::pair<Args...>& p)
 | 
			
		||||
{
 | 
			
		||||
    p = {j.at(0), j.at(1)};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BasicJsonType, typename Tuple, std::size_t... Idx>
 | 
			
		||||
void from_json_tuple_impl(const BasicJsonType& j, Tuple& t, index_sequence<Idx...>)
 | 
			
		||||
{
 | 
			
		||||
    t = std::make_tuple(j.at(Idx)...);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename BasicJsonType, typename... Args>
 | 
			
		||||
void from_json(const BasicJsonType& j, std::tuple<Args...>& t)
 | 
			
		||||
{
 | 
			
		||||
    from_json_tuple_impl(j, t, index_sequence_for<Args...> {});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct to_json_fn
 | 
			
		||||
{
 | 
			
		||||
  private:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -239,6 +239,59 @@ TEST_CASE("constructors")
 | 
			
		|||
            CHECK(j == j_reference);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        SECTION("std::pair")
 | 
			
		||||
        {
 | 
			
		||||
            std::pair<float, std::string> 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<std::pair<int, float>>();
 | 
			
		||||
            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<int> {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<std::tuple<int, float, std::string>>();
 | 
			
		||||
            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<std::pair<int, int>>()));
 | 
			
		||||
            CHECK_THROWS((j.get<std::tuple<int, int>>()));
 | 
			
		||||
            CHECK_THROWS((j.get<std::array<int, 3>>()));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        SECTION("std::forward_list<json>")
 | 
			
		||||
        {
 | 
			
		||||
            std::forward_list<json> 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<json, 5>")
 | 
			
		||||
        SECTION("std::array<json, 6>")
 | 
			
		||||
        {
 | 
			
		||||
            std::array<json, 6> 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<std::array<json, 6>>();
 | 
			
		||||
            CHECK(a2 == a);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        SECTION("std::vector<json>")
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue