diff --git a/include/boost/json/detail/parse_into.hpp b/include/boost/json/detail/parse_into.hpp index 003c8d3d1..d68fce1a9 100644 --- a/include/boost/json/detail/parse_into.hpp +++ b/include/boost/json/detail/parse_into.hpp @@ -18,6 +18,7 @@ #include #include +#include #include /* @@ -1152,7 +1153,7 @@ class converting_handler handler_tuple handlers_; int inner_active_ = -1; - std::size_t activated_ = 0; + std::bitset::value> seen_; public: converting_handler( converting_handler const& ) = delete; @@ -1184,7 +1185,7 @@ class converting_handler inner_active_, is_required_checker{}); if( required_member ) - ++activated_; + seen_[inner_active_] = true; key_ = {}; inner_active_ = -1; @@ -1214,7 +1215,17 @@ class converting_handler bool on_object_begin( system::error_code& ec ) { if( inner_active_ < 0 ) + { + // optional members count as seen from the start, so that at the + // end of the object seen_.all() means no required member is + // missing + mp11::mp_for_each< mp11::mp_iota< mp11::mp_size
> >( + [&](auto I) { + using T = mp11::mp_at< Dt, decltype(I) >; + seen_[I] = is_optional_like::value; + }); return true; + } BOOST_JSON_INVOKE_INNER( on_object_begin(ec) ); } @@ -1223,9 +1234,7 @@ class converting_handler { if( inner_active_ < 0 ) { - using C = mp11::mp_count_if; - constexpr int N = mp11::mp_size
::value - C::value; - if( activated_ < N ) + if( !seen_.all() ) { BOOST_JSON_FAIL( ec, error::size_mismatch ); return false; diff --git a/test/parse_into.cpp b/test/parse_into.cpp index 241591fea..2fa778184 100644 --- a/test/parse_into.cpp +++ b/test/parse_into.cpp @@ -426,6 +426,24 @@ class parse_into_test {"b", 3.14f}, {"c", "hello"}}}}; testParseIntoValue(unexpected_jo); + + system::error_code ec; + X x{}; + parse_into(x, R"( {"a": 1, "a": 2, "a": 3} )", ec); + BOOST_TEST( ec == error::size_mismatch ); + + std::vector v; + ec = {}; + parse_into( + v, R"( [{"a": 1, "b": 1, "c": "one"}, {"a": 2}] )", ec); + BOOST_TEST( ec == error::size_mismatch ); + + ec = {}; + parse_into( + v, + R"( [{"a": 1, "b": 1, "c": "one"}, {"a": 2, "b": 2, "c": "two"}] )", + ec); + BOOST_TEST( !ec.failed() ) && BOOST_TEST( v.size() == 2 ); #endif }