// // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) // Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // // Official repository: https://github.com/boostorg/json // #ifndef BOOST_JSON_DETAIL_PARSE_INTO_HPP #define BOOST_JSON_DETAIL_PARSE_INTO_HPP #include #include #include #include #include /* * This file contains the majority of parse_into functionality, specifically * the implementation of dedicated handlers for different generic categories of * types. * * At the core of parse_into is the specialisation basic_parser< * detail::into_handler >. detail::into_handler is a handler for * basic_parser. It directly handles events on_comment_part and on_comment (by * ignoring them), on_document_begin (by enabling the nested dedicated * handler), and on_document_end (by disabling the nested handler). * * Every other event is handled by the nested handler, which has the type * get_handler< T, into_handler >. The second parameter is the parent * handler (in this case, it's the top handler, into_handler). The type is * actually an alias to class template converting_handler, which has a separate * specialisation for every conversion category from the list of generic * conversion categories (e.g. sequence_conversion_tag, tuple_conversion_tag, * etc.) Instantiations of the template store a pointer to the parent handler * and a pointer to the value T. * * The nested handler handles specific parser events by setting error_code to * an appropriate value, if it receives an event it isn't supposed to handle * (e.g. a number handler getting an on_string event), and also updates the * value when appropriate. Note that they never need to handle on_comment_part, * on_comment, on_document_begin, and on_document_end events, as those are * always handled by the top handler into_handler. * * When the nested handler receives an event that completes the current value, * it is supposed to call its parent's signal_value member function. This is * necessary for correct handling of composite types (e.g. sequences). * * Finally, nested handlers should always call parent's signal_end member * function if they don't handle on_array_end themselves. This is necessary * to correctly handle nested composites (e.g. sequences inside sequences). * signal_end can return false and set error state when the containing parser * requires more elements. * * converting_handler instantiations for composite categories of types have * their own nested handlers, to which they themselves delegate events. For * complex types you will get a tree of handlers with into_handler as the * root and handlers for scalars as leaves. * * To reiterate, only into_handler has to handle on_comment_part, on_comment, * on_document_begin, and on_document_end; only handlers for composites and * into_handler has to provide signal_value and signal_end; all handlers * except for into_handler have to call their parent's signal_end from * their on_array_begin, if they don't handle it themselves; once a handler * receives an event that finishes its current value, it should call its * parent's signal_value. */ namespace boost { namespace json { namespace detail { template< class Impl, class T, class Parent > class converting_handler; // get_handler template< class V, class P > using get_handler = converting_handler< generic_conversion_category, V, P >; template class handler_error_base { public: handler_error_base() = default; handler_error_base( handler_error_base const& ) = delete; handler_error_base& operator=( handler_error_base const& ) = delete; public: bool on_object_begin( system::error_code& ec ) { BOOST_JSON_FAIL( ec, E ); return false; } bool on_array_begin( system::error_code& ec ) { BOOST_JSON_FAIL( ec, E ); return false; } bool on_array_end( system::error_code& ec ) { BOOST_JSON_FAIL( ec, E ); return false; } bool on_string_part( system::error_code& ec, string_view ) { BOOST_JSON_FAIL( ec, E ); return false; } bool on_string( system::error_code& ec, string_view ) { BOOST_JSON_FAIL( ec, E ); return false; } bool on_number_part( system::error_code& ec ) { BOOST_JSON_FAIL( ec, E ); return false; } bool on_int64( system::error_code& ec, std::int64_t ) { BOOST_JSON_FAIL( ec, E ); return false; } bool on_uint64( system::error_code& ec, std::uint64_t ) { BOOST_JSON_FAIL( ec, E ); return false; } bool on_double( system::error_code& ec, double ) { BOOST_JSON_FAIL( ec, E ); return false; } bool on_bool( system::error_code& ec, bool ) { BOOST_JSON_FAIL( ec, E ); return false; } bool on_null( system::error_code& ec ) { BOOST_JSON_FAIL( ec, E ); return false; } // LCOV_EXCL_START // parses that can't handle this would fail at on_object_begin bool on_object_end( system::error_code& ) { BOOST_ASSERT( false ); return false; } bool on_key_part( system::error_code& ec, string_view ) { BOOST_JSON_FAIL( ec, E ); return false; } bool on_key( system::error_code& ec, string_view ) { BOOST_JSON_FAIL( ec, E ); return false; } // LCOV_EXCL_STOP }; template< class P, error E > class scalar_handler : public handler_error_base { protected: P* parent_; public: scalar_handler(scalar_handler const&) = delete; scalar_handler& operator=(scalar_handler const&) = delete; scalar_handler(P* p): parent_( p ) {} bool on_array_end( system::error_code& ec ) { return parent_->signal_end(ec); } }; template< class D, class V, class P, error E > class composite_handler { protected: using inner_handler_type = get_handler; P* parent_; #if defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wmissing-field-initializers" #endif V next_value_ = {}; inner_handler_type inner_; bool inner_active_ = false; public: composite_handler( composite_handler const& ) = delete; composite_handler& operator=( composite_handler const& ) = delete; composite_handler( P* p ) : parent_(p), inner_( &next_value_, static_cast(this) ) {} #if defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__) # pragma GCC diagnostic pop #endif bool signal_end(system::error_code&) { inner_active_ = false; parent_->signal_value(); return true; } #define BOOST_JSON_INVOKE_INNER(f) \ if( !inner_active_ ) { \ BOOST_JSON_FAIL(ec, E); \ return false; \ } \ else \ return inner_.f bool on_object_begin( system::error_code& ec ) { BOOST_JSON_INVOKE_INNER( on_object_begin(ec) ); } bool on_object_end( system::error_code& ec ) { BOOST_JSON_INVOKE_INNER( on_object_end(ec) ); } bool on_array_begin( system::error_code& ec ) { BOOST_JSON_INVOKE_INNER( on_array_begin(ec) ); } bool on_array_end( system::error_code& ec ) { BOOST_JSON_INVOKE_INNER( on_array_end(ec) ); } bool on_key_part( system::error_code& ec, string_view sv ) { BOOST_JSON_INVOKE_INNER( on_key_part(ec, sv) ); } bool on_key( system::error_code& ec, string_view sv ) { BOOST_JSON_INVOKE_INNER( on_key(ec, sv) ); } bool on_string_part( system::error_code& ec, string_view sv ) { BOOST_JSON_INVOKE_INNER( on_string_part(ec, sv) ); } bool on_string( system::error_code& ec, string_view sv ) { BOOST_JSON_INVOKE_INNER( on_string(ec, sv) ); } bool on_number_part( system::error_code& ec ) { BOOST_JSON_INVOKE_INNER( on_number_part(ec) ); } bool on_int64( system::error_code& ec, std::int64_t v ) { BOOST_JSON_INVOKE_INNER( on_int64(ec, v) ); } bool on_uint64( system::error_code& ec, std::uint64_t v ) { BOOST_JSON_INVOKE_INNER( on_uint64(ec, v) ); } bool on_double( system::error_code& ec, double v ) { BOOST_JSON_INVOKE_INNER( on_double(ec, v) ); } bool on_bool( system::error_code& ec, bool v ) { BOOST_JSON_INVOKE_INNER( on_bool(ec, v) ); } bool on_null( system::error_code& ec ) { BOOST_JSON_INVOKE_INNER( on_null(ec) ); } #undef BOOST_JSON_INVOKE_INNER }; // integral handler template::value, int>::type = 0> bool integral_in_range( std::int64_t v ) { return v >= (std::numeric_limits::min)() && v <= (std::numeric_limits::max)(); } template::value, int>::type = 0> bool integral_in_range( std::int64_t v ) { return v >= 0 && static_cast( v ) <= (std::numeric_limits::max)(); } template bool integral_in_range( std::uint64_t v ) { return v <= static_cast::type>( (std::numeric_limits::max)() ); } template< class V, class P > class converting_handler : public scalar_handler { private: V* value_; public: converting_handler( V* v, P* p ) : converting_handler::scalar_handler(p) , value_(v) {} bool on_number_part( system::error_code& ) { return true; } bool on_int64( system::error_code& ec, std::int64_t v ) { if( !integral_in_range( v ) ) { BOOST_JSON_FAIL( ec, error::not_exact ); return false; } *value_ = static_cast( v ); this->parent_->signal_value(); return true; } bool on_uint64( system::error_code& ec, std::uint64_t v ) { if( !integral_in_range( v ) ) { BOOST_JSON_FAIL( ec, error::not_exact ); return false; } *value_ = static_cast( v ); this->parent_->signal_value(); return true; } }; // floating point handler template< class V, class P> class converting_handler : public scalar_handler { private: V* value_; public: converting_handler( V* v, P* p ) : converting_handler::scalar_handler(p) , value_(v) {} bool on_number_part( system::error_code& ) { return true; } bool on_int64( system::error_code&, std::int64_t v ) { *value_ = static_cast( v ); this->parent_->signal_value(); return true; } bool on_uint64( system::error_code&, std::uint64_t v ) { *value_ = static_cast( v ); this->parent_->signal_value(); return true; } bool on_double( system::error_code&, double v ) { *value_ = static_cast( v ); this->parent_->signal_value(); return true; } }; // string handler template< class V, class P > class converting_handler : public scalar_handler { private: V* value_; bool cleared_ = false; public: converting_handler( V* v, P* p ) : converting_handler::scalar_handler(p) , value_(v) {} bool on_string_part( system::error_code&, string_view sv ) { if( !cleared_ ) { cleared_ = true; value_->clear(); } value_->append( sv.begin(), sv.end() ); return true; } bool on_string( system::error_code&, string_view sv ) { if( !cleared_ ) value_->clear(); else cleared_ = false; value_->append( sv.begin(), sv.end() ); this->parent_->signal_value(); return true; } }; // bool handler template< class V, class P > class converting_handler : public scalar_handler { private: V* value_; public: converting_handler( V* v, P* p ) : converting_handler::scalar_handler(p) , value_(v) {} bool on_bool( system::error_code&, bool v ) { *value_ = v; this->parent_->signal_value(); return true; } }; // null handler template< class V, class P > class converting_handler : public scalar_handler { private: V* value_; public: converting_handler( V* v, P* p ) : converting_handler::scalar_handler(p) , value_(v) {} bool on_null( system::error_code& ) { *value_ = {}; this->parent_->signal_value(); return true; } }; // described enum handler template< class V, class P > class converting_handler : public scalar_handler { #ifndef BOOST_DESCRIBE_CXX14 static_assert( sizeof(V) == 0, "Enum support for parse_into requires C++14" ); #else private: V* value_; std::string name_; public: converting_handler( V* v, P* p ) : converting_handler::scalar_handler(p) , value_(v) {} bool on_string_part( system::error_code&, string_view sv ) { name_.append( sv.begin(), sv.end() ); return true; } bool on_string( system::error_code& ec, string_view sv ) { string_view name = sv; if( !name_.empty() ) { name_.append( sv.begin(), sv.end() ); name = name_; } if( !describe::enum_from_string(name, *value_) ) { BOOST_JSON_FAIL(ec, error::unknown_name); return false; } this->parent_->signal_value(); return true; } #endif // BOOST_DESCRIBE_CXX14 }; template< class V, class P > class converting_handler { static_assert( sizeof(V) == 0, "This type is not supported" ); }; // sequence handler template< class It > bool check_inserter( It l, It r ) { return l == r; } template< class It1, class It2 > std::true_type check_inserter( It1, It2 ) { return {}; } template void clear_container( T&, mp11::mp_int<2>) { } template void clear_container( T& target, mp11::mp_int<1>) { target.clear(); } template void clear_container( T& target, mp11::mp_int<0>) { target.clear(); } template< class V, class P > class converting_handler : public composite_handler< converting_handler, detail::value_type, P, error::not_array> { private: V* value_; using Inserter = decltype( detail::inserter(*value_, inserter_implementation()) ); Inserter inserter; public: converting_handler( V* v, P* p ) : converting_handler::composite_handler(p) , value_(v) , inserter( detail::inserter(*value_, inserter_implementation()) ) {} void signal_value() { *inserter++ = std::move(this->next_value_); #if defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wmissing-field-initializers" #endif this->next_value_ = {}; #if defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__) # pragma GCC diagnostic pop #endif } bool signal_end(system::error_code& ec) { if( !check_inserter( inserter, value_->end() ) ) { BOOST_JSON_FAIL( ec, error::size_mismatch ); return false; } inserter = detail::inserter(*value_, inserter_implementation()); return converting_handler::composite_handler::signal_end(ec); } bool on_array_begin( system::error_code& ec ) { if( this->inner_active_ ) return this->inner_.on_array_begin( ec ); this->inner_active_ = true; clear_container( *value_, inserter_implementation() ); return true; } bool on_array_end( system::error_code& ec ) { if( this->inner_active_ ) return this->inner_.on_array_end( ec ); return this->parent_->signal_end(ec); } }; // map handler template< class V, class P > class converting_handler : public composite_handler< converting_handler, detail::mapped_type, P, error::not_object> { private: V* value_; std::string key_; public: converting_handler( V* v, P* p ) : converting_handler::composite_handler(p), value_(v) {} void signal_value() { value_->emplace( std::move(key_), std::move(this->next_value_) ); key_ = {}; this->next_value_ = {}; this->inner_active_ = false; } bool on_object_begin( system::error_code& ec ) { if( this->inner_active_ ) return this->inner_.on_object_begin(ec); clear_container( *value_, inserter_implementation() ); return true; } bool on_object_end( system::error_code& ec ) { if( this->inner_active_ ) return this->inner_.on_object_end(ec); this->parent_->signal_value(); return true; } bool on_array_end( system::error_code& ec ) { if( this->inner_active_ ) return this->inner_.on_array_end(ec); return this->parent_->signal_end(ec); } bool on_key_part( system::error_code& ec, string_view sv ) { if( this->inner_active_ ) return this->inner_.on_key_part(ec, sv); key_.append( sv.data(), sv.size() ); return true; } bool on_key( system::error_code& ec, string_view sv ) { if( this->inner_active_ ) return this->inner_.on_key(ec, sv); key_.append( sv.data(), sv.size() ); this->inner_active_ = true; return true; } }; // tuple handler template struct handler_tuple_element { template< class... Args > handler_tuple_element( Args&& ... args ) : t_( static_cast(args)... ) {} T t_; }; template T& get( handler_tuple_element& e ) { return e.t_; } template< class P, class LV, class S = mp11::make_index_sequence::value> > struct handler_tuple; template< class P, template class L, class... V, std::size_t... I > struct handler_tuple< P, L, mp11::index_sequence > : handler_tuple_element< I, get_handler > ... { handler_tuple( handler_tuple const& ) = delete; handler_tuple& operator=( handler_tuple const& ) = delete; template< class Access, class T > handler_tuple( Access access, T* pv, P* pp ) : handler_tuple_element< I, get_handler >( access( pv, mp11::mp_int() ), pp ) ... { } }; #if defined(BOOST_MSVC) && BOOST_MSVC < 1910 template< class T > struct tuple_element_list_impl { template< class I > using tuple_element_helper = tuple_element_t; using type = mp11::mp_transform< tuple_element_helper, mp11::mp_iota< std::tuple_size > >; }; template< class T > using tuple_element_list = typename tuple_element_list_impl::type; #else template< class I, class T > using tuple_element_helper = tuple_element_t; template< class T > using tuple_element_list = mp11::mp_transform_q< mp11::mp_bind_back< tuple_element_helper, T>, mp11::mp_iota< std::tuple_size > >; #endif template< class Op, class... Args> struct handler_op_invoker { public: std::tuple args; template< class Handler > bool operator()( Handler& handler ) const { return (*this)( handler, mp11::index_sequence_for() ); } private: template< class Handler, std::size_t... I > bool operator()( Handler& handler, mp11::index_sequence ) const { return Op()( handler, std::get(args)... ); } }; template< class Handlers, class F > struct tuple_handler_op_invoker { Handlers& handlers; F fn; template< class I > bool operator()( I ) const { return fn( get(handlers) ); } }; struct tuple_accessor { template< class T, class I > auto operator()( T* t, I ) const -> tuple_element_t* { using std::get; return &get(*t); } }; template< class T, class P > class converting_handler { private: T* value_; P* parent_; handler_tuple< converting_handler, tuple_element_list > handlers_; int inner_active_ = -1; public: converting_handler( converting_handler const& ) = delete; converting_handler& operator=( converting_handler const& ) = delete; converting_handler( T* v, P* p ) : value_(v) , parent_(p) , handlers_(tuple_accessor(), v, this) {} void signal_value() { ++inner_active_; } bool signal_end(system::error_code& ec) { constexpr int N = std::tuple_size::value; if( inner_active_ < N ) { BOOST_JSON_FAIL( ec, error::size_mismatch ); return true; } inner_active_ = -1; parent_->signal_value(); return true; } #define BOOST_JSON_HANDLE_EVENT(fn) \ struct do_ ## fn \ { \ template< class H, class... Args > \ bool operator()( H& h, Args& ... args ) const \ { \ return h. fn (args...); \ } \ }; \ \ template< class... Args > \ bool fn( system::error_code& ec, Args&& ... args ) \ { \ if( inner_active_ < 0 ) \ { \ BOOST_JSON_FAIL( ec, error::not_array ); \ return false; \ } \ constexpr int N = std::tuple_size::value; \ if( inner_active_ >= N ) \ { \ BOOST_JSON_FAIL( ec, error::size_mismatch ); \ return false; \ } \ using F = handler_op_invoker< do_ ## fn, system::error_code, Args...>; \ using H = decltype(handlers_); \ return mp11::mp_with_index( \ inner_active_, \ tuple_handler_op_invoker{ \ handlers_, \ F{ std::forward_as_tuple(ec, args...) } } ); \ } BOOST_JSON_HANDLE_EVENT( on_object_begin ) BOOST_JSON_HANDLE_EVENT( on_object_end ) struct do_on_array_begin { handler_tuple< converting_handler, tuple_element_list >& handlers; system::error_code& ec; template< class I > bool operator()( I ) const { return get(handlers).on_array_begin(ec); } }; bool on_array_begin( system::error_code& ec ) { if( inner_active_ < 0 ) { inner_active_ = 0; return true; } constexpr int N = std::tuple_size::value; if( inner_active_ >= N ) { BOOST_JSON_FAIL( ec, error::size_mismatch ); return false; } return mp11::mp_with_index( inner_active_, do_on_array_begin{handlers_, ec} ); } struct do_on_array_end { handler_tuple< converting_handler, tuple_element_list >& handlers; system::error_code& ec; template< class I > bool operator()( I ) const { return get(handlers).on_array_end(ec); } }; bool on_array_end( system::error_code& ec ) { if( inner_active_ < 0 ) return parent_->signal_end(ec); constexpr int N = std::tuple_size::value; if( inner_active_ >= N ) return signal_end(ec); return mp11::mp_with_index( inner_active_, do_on_array_end{handlers_, ec} ); } BOOST_JSON_HANDLE_EVENT( on_key_part ) BOOST_JSON_HANDLE_EVENT( on_key ) BOOST_JSON_HANDLE_EVENT( on_string_part ) BOOST_JSON_HANDLE_EVENT( on_string ) BOOST_JSON_HANDLE_EVENT( on_number_part ) BOOST_JSON_HANDLE_EVENT( on_int64 ) BOOST_JSON_HANDLE_EVENT( on_uint64 ) BOOST_JSON_HANDLE_EVENT( on_double ) BOOST_JSON_HANDLE_EVENT( on_bool ) BOOST_JSON_HANDLE_EVENT( on_null ) #undef BOOST_JSON_HANDLE_EVENT }; // described struct handler #if defined(BOOST_MSVC) && BOOST_MSVC < 1910 template< class T > struct struct_element_list_impl { template< class D > using helper = described_member_t; using type = mp11::mp_transform< helper, described_members >; }; template< class T > using struct_element_list = typename struct_element_list_impl::type; #else template< class T > using struct_element_list = mp11::mp_transform_q< mp11::mp_bind_front< described_member_t, T >, described_members >; #endif struct struct_accessor { template< class T, class I > auto operator()( T* t, I ) const -> described_member_t, I> >* { using Ds = described_members; using D = mp11::mp_at; return &(t->*D::pointer); } }; template< class F > struct struct_key_searcher { F fn; template< class D > void operator()( D ) const { fn( D::name ) ; } }; template class converting_handler { #if !defined(BOOST_DESCRIBE_CXX14) static_assert( sizeof(V) == 0, "Struct support for parse_into requires C++14" ); #else private: V* value_; P* parent_; std::string key_; using Dm = described_members; handler_tuple< converting_handler, struct_element_list > handlers_; int inner_active_ = -1; std::size_t activated_ = 0; public: converting_handler( converting_handler const& ) = delete; converting_handler& operator=( converting_handler const& ) = delete; converting_handler( V* v, P* p ) : value_(v), parent_(p), handlers_(struct_accessor(), v, this) {} struct is_optional_checker { template< class I > bool operator()( I ) const noexcept { using L = struct_element_list; using T = mp11::mp_at; return !is_optional_like::value; } }; void signal_value() { BOOST_ASSERT( inner_active_ >= 0 ); bool required_member = mp11::mp_with_index< mp11::mp_size >( inner_active_, is_optional_checker{}); if( required_member ) ++activated_; key_ = {}; inner_active_ = -1; } bool signal_end(system::error_code&) { key_ = {}; inner_active_ = -1; parent_->signal_value(); return true; } #define BOOST_JSON_INVOKE_INNER(fn) \ if( inner_active_ < 0 ) \ { \ BOOST_JSON_FAIL( ec, error::not_object ); \ return false; \ } \ auto f = [&](auto& handler) { return handler.fn ; }; \ using F = decltype(f); \ using H = decltype(handlers_); \ return mp11::mp_with_index< mp11::mp_size >( \ inner_active_, \ tuple_handler_op_invoker{handlers_, f} ); bool on_object_begin( system::error_code& ec ) { if( inner_active_ < 0 ) return true; BOOST_JSON_INVOKE_INNER( on_object_begin(ec) ); } bool on_object_end( system::error_code& ec ) { if( inner_active_ < 0 ) { using L = struct_element_list; using C = mp11::mp_count_if; constexpr int N = mp11::mp_size::value - C::value; if( activated_ < N ) { BOOST_JSON_FAIL( ec, error::size_mismatch ); return false; } parent_->signal_value(); return true; } BOOST_JSON_INVOKE_INNER( on_object_end(ec) ); } bool on_array_begin( system::error_code& ec ) { BOOST_JSON_INVOKE_INNER( on_array_begin(ec) ); } bool on_array_end( system::error_code& ec ) { if( inner_active_ < 0 ) return parent_->signal_end(ec); BOOST_JSON_INVOKE_INNER( on_array_end(ec) ); } bool on_key_part( system::error_code& ec, string_view sv ) { if( inner_active_ < 0 ) { key_.append( sv.data(), sv.size() ); return true; } BOOST_JSON_INVOKE_INNER( on_key_part(ec, sv) ); } bool on_key( system::error_code& ec, string_view sv ) { if( inner_active_ >= 0 ) { BOOST_JSON_INVOKE_INNER( on_key(ec, sv) ); } string_view key = sv; if( !key_.empty() ) { key_.append( sv.data(), sv.size() ); key = key_; } int i = 0; auto f = [&](char const* name) { if( key == name ) inner_active_ = i; ++i; }; mp11::mp_for_each( struct_key_searcher{f} ); if( inner_active_ < 0 ) { BOOST_JSON_FAIL(ec, error::unknown_name); return false; } return true; } bool on_string_part( system::error_code& ec, string_view sv ) { BOOST_JSON_INVOKE_INNER( on_string_part(ec, sv) ); } bool on_string( system::error_code& ec, string_view sv ) { BOOST_JSON_INVOKE_INNER( on_string(ec, sv) ); } bool on_number_part( system::error_code& ec ) { BOOST_JSON_INVOKE_INNER( on_number_part(ec) ); } bool on_int64( system::error_code& ec, std::int64_t v ) { BOOST_JSON_INVOKE_INNER( on_int64(ec, v) ); } bool on_uint64( system::error_code& ec, std::uint64_t v ) { BOOST_JSON_INVOKE_INNER( on_uint64(ec, v) ); } bool on_double( system::error_code& ec, double v ) { BOOST_JSON_INVOKE_INNER( on_double(ec, v) ); } bool on_bool( system::error_code& ec, bool v ) { BOOST_JSON_INVOKE_INNER( on_bool(ec, v) ); } bool on_null( system::error_code& ec ) { BOOST_JSON_INVOKE_INNER( on_null(ec) ); } #undef BOOST_JSON_INVOKE_INNER #endif }; // variant handler struct object_begin_handler_event { }; struct object_end_handler_event { }; struct array_begin_handler_event { }; struct array_end_handler_event { }; struct key_handler_event { std::string value; }; struct string_handler_event { std::string value; }; struct int64_handler_event { std::int64_t value; }; struct uint64_handler_event { std::uint64_t value; }; struct double_handler_event { double value; }; struct bool_handler_event { bool value; }; struct null_handler_event { }; using parse_event = variant2::variant< object_begin_handler_event, object_end_handler_event, array_begin_handler_event, array_end_handler_event, key_handler_event, string_handler_event, int64_handler_event, uint64_handler_event, double_handler_event, bool_handler_event, null_handler_event>; template< class H > struct event_visitor { H& handler; system::error_code& ec; bool operator()(object_begin_handler_event&) const { return handler.on_object_begin(ec); } bool operator()(object_end_handler_event&) const { return handler.on_object_end(ec); } bool operator()(array_begin_handler_event&) const { return handler.on_array_begin(ec); } bool operator()(array_end_handler_event&) const { return handler.on_array_end(ec); } bool operator()(key_handler_event& ev) const { return handler.on_key(ec, ev.value); } bool operator()(string_handler_event& ev) const { return handler.on_string(ec, ev.value); } bool operator()(int64_handler_event& ev) const { return handler.on_int64(ec, ev.value); } bool operator()(uint64_handler_event& ev) const { return handler.on_uint64(ec, ev.value); } bool operator()(double_handler_event& ev) const { return handler.on_double(ec, ev.value); } bool operator()(bool_handler_event& ev) const { return handler.on_bool(ec, ev.value); } bool operator()(null_handler_event&) const { return handler.on_null(ec); } }; // L -> variant< monostate, get_handler... > template< class P, class L > using inner_handler_variant = mp11::mp_push_front< mp11::mp_transform_q< mp11::mp_bind_back, mp11::mp_apply>, variant2::monostate>; template< class T, class P > class converting_handler { private: using variant_size = mp11::mp_size; T* value_; P* parent_; std::string string_; std::vector< parse_event > events_; inner_handler_variant inner_; int inner_active_ = -1; public: converting_handler( converting_handler const& ) = delete; converting_handler& operator=( converting_handler const& ) = delete; converting_handler( T* v, P* p ) : value_( v ) , parent_( p ) {} void signal_value() { inner_.template emplace<0>(); inner_active_ = -1; events_.clear(); parent_->signal_value(); } bool signal_end(system::error_code& ec) { return parent_->signal_end(ec); } struct alternative_selector { converting_handler* self; template< class I > void operator()( I ) const { using V = mp11::mp_at; auto& v = self->value_->template emplace( V{} ); self->inner_.template emplace(&v, self); } }; void next_alternative() { if( ++inner_active_ >= static_cast(variant_size::value) ) return; mp11::mp_with_index< variant_size::value >( inner_active_, alternative_selector{this} ); } struct event_processor { converting_handler* self; system::error_code& ec; parse_event& event; template< class I > bool operator()( I ) const { auto& handler = variant2::get(self->inner_); using Handler = remove_cvref; return variant2::visit( event_visitor{handler, ec}, event ); } }; bool process_events(system::error_code& ec) { constexpr std::size_t N = variant_size::value; // should be pointers not iterators, otherwise MSVC crashes auto const last = events_.data() + events_.size(); auto first = last - 1; bool ok = false; if( inner_active_ < 0 ) next_alternative(); do { if( static_cast(inner_active_) >= N ) { BOOST_JSON_FAIL( ec, error::exhausted_variants ); return false; } for ( ; first != last; ++first ) { ok = mp11::mp_with_index< N >( inner_active_, event_processor{this, ec, *first} ); if( !ok ) { first = events_.data(); next_alternative(); ec.clear(); break; } } } while( !ok ); return true; } #define BOOST_JSON_INVOKE_INNER(ev, ec) \ events_.emplace_back( ev ); \ return process_events(ec); bool on_object_begin( system::error_code& ec ) { BOOST_JSON_INVOKE_INNER( object_begin_handler_event{}, ec ); } bool on_object_end( system::error_code& ec ) { BOOST_JSON_INVOKE_INNER( object_end_handler_event{}, ec ); } bool on_array_begin( system::error_code& ec ) { BOOST_JSON_INVOKE_INNER( array_begin_handler_event{}, ec ); } bool on_array_end( system::error_code& ec ) { if( !inner_active_ ) return signal_end(ec); BOOST_JSON_INVOKE_INNER( array_end_handler_event{}, ec ); } bool on_key_part( system::error_code&, string_view sv ) { string_.append(sv); return true; } bool on_key( system::error_code& ec, string_view sv ) { string_.append(sv); BOOST_JSON_INVOKE_INNER( key_handler_event{ std::move(string_) }, ec ); } bool on_string_part( system::error_code&, string_view sv ) { string_.append(sv); return true; } bool on_string( system::error_code& ec, string_view sv ) { string_.append(sv); BOOST_JSON_INVOKE_INNER( string_handler_event{ std::move(string_) }, ec ); } bool on_number_part( system::error_code& ) { return true; } bool on_int64( system::error_code& ec, std::int64_t v ) { BOOST_JSON_INVOKE_INNER( int64_handler_event{v}, ec ); } bool on_uint64( system::error_code& ec, std::uint64_t v ) { BOOST_JSON_INVOKE_INNER( uint64_handler_event{v}, ec ); } bool on_double( system::error_code& ec, double v ) { BOOST_JSON_INVOKE_INNER( double_handler_event{v}, ec ); } bool on_bool( system::error_code& ec, bool v ) { BOOST_JSON_INVOKE_INNER( bool_handler_event{v}, ec ); } bool on_null( system::error_code& ec ) { BOOST_JSON_INVOKE_INNER( null_handler_event{}, ec ); } #undef BOOST_JSON_INVOKE_INNER }; // optional handler template class converting_handler { private: using inner_type = value_result_type; using inner_handler_type = get_handler; V* value_; P* parent_; inner_type inner_value_ = {}; inner_handler_type inner_; bool inner_active_ = false; public: converting_handler( converting_handler const& ) = delete; converting_handler& operator=( converting_handler const& ) = delete; converting_handler( V* v, P* p ) : value_(v), parent_(p), inner_(&inner_value_, this) {} void signal_value() { *value_ = std::move(inner_value_); inner_active_ = false; parent_->signal_value(); } bool signal_end(system::error_code& ec) { return parent_->signal_end(ec); } #define BOOST_JSON_INVOKE_INNER(fn) \ if( !inner_active_ ) \ inner_active_ = true; \ return inner_.fn; bool on_object_begin( system::error_code& ec ) { BOOST_JSON_INVOKE_INNER( on_object_begin(ec) ); } bool on_object_end( system::error_code& ec ) { BOOST_JSON_INVOKE_INNER( on_object_end(ec) ); } bool on_array_begin( system::error_code& ec ) { BOOST_JSON_INVOKE_INNER( on_array_begin(ec) ); } bool on_array_end( system::error_code& ec ) { if( !inner_active_ ) return signal_end(ec); BOOST_JSON_INVOKE_INNER( on_array_end(ec) ); } bool on_key_part( system::error_code& ec, string_view sv ) { BOOST_JSON_INVOKE_INNER( on_key_part(ec, sv) ); } bool on_key( system::error_code& ec, string_view sv ) { BOOST_JSON_INVOKE_INNER( on_key(ec, sv) ); } bool on_string_part( system::error_code& ec, string_view sv ) { BOOST_JSON_INVOKE_INNER( on_string_part(ec, sv) ); } bool on_string( system::error_code& ec, string_view sv ) { BOOST_JSON_INVOKE_INNER( on_string(ec, sv) ); } bool on_number_part( system::error_code& ec ) { BOOST_JSON_INVOKE_INNER( on_number_part(ec) ); } bool on_int64( system::error_code& ec, std::int64_t v ) { BOOST_JSON_INVOKE_INNER( on_int64(ec, v) ); } bool on_uint64( system::error_code& ec, std::uint64_t v ) { BOOST_JSON_INVOKE_INNER( on_uint64(ec, v) ); } bool on_double( system::error_code& ec, double v ) { BOOST_JSON_INVOKE_INNER( on_double(ec, v) ); } bool on_bool( system::error_code& ec, bool v ) { BOOST_JSON_INVOKE_INNER( on_bool(ec, v) ); } bool on_null( system::error_code& ec ) { if( !inner_active_ ) { *value_ = {}; this->parent_->signal_value(); return true; } else { return inner_.on_null(ec); } } #undef BOOST_JSON_INVOKE_INNER }; // path handler template< class V, class P > class converting_handler : public scalar_handler { private: V* value_; bool cleared_ = false; public: converting_handler( V* v, P* p ) : converting_handler::scalar_handler(p) , value_(v) {} bool on_string_part( system::error_code&, string_view sv ) { if( !cleared_ ) { cleared_ = true; value_->clear(); } value_->concat( sv.begin(), sv.end() ); return true; } bool on_string( system::error_code&, string_view sv ) { if( !cleared_ ) value_->clear(); else cleared_ = false; value_->concat( sv.begin(), sv.end() ); this->parent_->signal_value(); return true; } }; // into_handler template< class V > class into_handler { private: using inner_handler_type = get_handler; inner_handler_type inner_; bool inner_active_ = true; public: into_handler( into_handler const& ) = delete; into_handler& operator=( into_handler const& ) = delete; public: static constexpr std::size_t max_object_size = object::max_size(); static constexpr std::size_t max_array_size = array::max_size(); static constexpr std::size_t max_key_size = string::max_size(); static constexpr std::size_t max_string_size = string::max_size(); public: explicit into_handler( V* v ): inner_( v, this ) { } void signal_value() { } bool signal_end(system::error_code&) { return true; } bool on_document_begin( system::error_code& ) { return true; } bool on_document_end( system::error_code& ) { inner_active_ = false; return true; } #define BOOST_JSON_INVOKE_INNER(f) \ if( !inner_active_ ) \ { \ BOOST_JSON_FAIL( ec, error::extra_data ); \ return false; \ } \ else \ return inner_.f bool on_object_begin( system::error_code& ec ) { BOOST_JSON_INVOKE_INNER( on_object_begin(ec) ); } bool on_object_end( std::size_t, system::error_code& ec ) { BOOST_JSON_INVOKE_INNER( on_object_end(ec) ); } bool on_array_begin( system::error_code& ec ) { BOOST_JSON_INVOKE_INNER( on_array_begin(ec) ); } bool on_array_end( std::size_t, system::error_code& ec ) { BOOST_JSON_INVOKE_INNER( on_array_end(ec) ); } bool on_key_part( string_view sv, std::size_t, system::error_code& ec ) { BOOST_JSON_INVOKE_INNER( on_key_part(ec, sv) ); } bool on_key( string_view sv, std::size_t, system::error_code& ec ) { BOOST_JSON_INVOKE_INNER( on_key(ec, sv) ); } bool on_string_part( string_view sv, std::size_t, system::error_code& ec ) { BOOST_JSON_INVOKE_INNER( on_string_part(ec, sv) ); } bool on_string( string_view sv, std::size_t, system::error_code& ec ) { BOOST_JSON_INVOKE_INNER( on_string(ec, sv) ); } bool on_number_part( string_view, system::error_code& ec ) { BOOST_JSON_INVOKE_INNER( on_number_part(ec) ); } bool on_int64( std::int64_t v, string_view, system::error_code& ec ) { BOOST_JSON_INVOKE_INNER( on_int64(ec, v) ); } bool on_uint64( std::uint64_t v, string_view, system::error_code& ec ) { BOOST_JSON_INVOKE_INNER( on_uint64(ec, v) ); } bool on_double( double v, string_view, system::error_code& ec ) { BOOST_JSON_INVOKE_INNER( on_double(ec, v) ); } bool on_bool( bool v, system::error_code& ec ) { BOOST_JSON_INVOKE_INNER( on_bool(ec, v) ); } bool on_null( system::error_code& ec ) { BOOST_JSON_INVOKE_INNER( on_null(ec) ); } bool on_comment_part(string_view, system::error_code&) { return true; } bool on_comment(string_view, system::error_code&) { return true; } #undef BOOST_JSON_INVOKE_INNER }; } // namespace detail } // namespace boost } // namespace json #endif